OCaml 中的状态 monad
我试图在 OCaml 中实现状态 monad(作为练习)。我的实现如下所示:
module type MONAD_BUILDER =
sig
type 'a t
val return : 'a -> 'a t
val bind : 'a t -> ('a -> 'b t) -> 'b t
end;;
module MonadBuilder = functor (M: MONAD_BUILDER) ->
struct
let ( >>= ) = M.bind
let return = M.return
end;;
module StateM =
struct
type 'a state = { state: 's . 's -> ('a * 's) }
type 'a t = 'a state
let return x = { state = fun s -> (x, s) }
let bind m f =
let aux s =
let (x, s') = m.state s in
(f x).state s'
in { state = aux }
let run m x = fst (m.state x)
end;;
我为记录字段选择了存在类型,因为我不喜欢使用函子并将状态类型包装在模块中的想法。上面的实现有效,但是我 在实现 getState
和 setState
时遇到问题。我尝试像这样实现它们:
let getState = { state = fun s -> (s, s) }
let setState s = { state = fun _ -> ((), s) }
这不起作用,因为推断的字段类型,例如 'a -> ('a * 'a)
和 'a -> (unit * 'a)
比声明的类型 的通用性较差。的-> ('a * 's)
。我明白为什么会发生这种情况,但我想知道是否有另一种方法可以使用记录方法使其发挥作用?
谢谢。
干杯, 亚历克斯
I was trying to implement the state monad in OCaml (as an exercise). My implementation looks like this:
module type MONAD_BUILDER =
sig
type 'a t
val return : 'a -> 'a t
val bind : 'a t -> ('a -> 'b t) -> 'b t
end;;
module MonadBuilder = functor (M: MONAD_BUILDER) ->
struct
let ( >>= ) = M.bind
let return = M.return
end;;
module StateM =
struct
type 'a state = { state: 's . 's -> ('a * 's) }
type 'a t = 'a state
let return x = { state = fun s -> (x, s) }
let bind m f =
let aux s =
let (x, s') = m.state s in
(f x).state s'
in { state = aux }
let run m x = fst (m.state x)
end;;
I chose the existential type for the record field since I don't like the idea of using a functor and wrapping the state type in a module. The above implementation works, but I
ran into a problem while implementing getState
and setState
. I tried to implement them like:
let getState = { state = fun s -> (s, s) }
let setState s = { state = fun _ -> ((), s) }
This doesn't work since the inferred field types, e.g. 'a -> ('a * 'a)
and 'a -> (unit * 'a)
, are less generic than the declared type 's . 's -> ('a * 's)
. I understand why this is happening, but I was wondering if there is another way of making it work using the record approach?
Thanks.
Cheers,
Alex
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
<代码>的。的-> ('a * 's) 是通用类型。你将很难用通用类型实现状态......
没有使用模块的情况下封装存在类型的干净方法(因为存在类型是抽象类型的用途)。
当然,您可以改为发布状态类型:
或者更短,
使用附加参数,您的代码将运行。但是,您会遇到这样一个事实:您的参数必须由 monad 处理。因此,您可以在构建 monad 时隐藏它:
或者更改 monad 设计以合并用于存在类型的附加类型参数:
's. 's -> ('a * 's)
is an universal type. You're going to have a hard time implementing a state with universal types...There's no clean way of encapsulating an existential type there without using a module (because existential types is what abstract types are for).
You could, of course, publish the state type instead:
Or even shorter,
With the additional parameter, your code runs. However, you run into the fact that your parameter must be handled by the monad. So, you can either hide it when building the monad:
Or alter your monad design to incorporate an additional type parameter that is to be used for existential types: