包裹状态monad有什么好处?

时间:2013-11-24 22:31:40

标签: f# state-monad

这个可能是一个愚蠢的,但看看(Eliminating my explicit state passing via like, monads and stuff

type State<'s,'a> = State of ('s -> 'a * 's)

type StateBuilder<'s>() =
  member x.Return v : State<'s,_> = State(fun s -> v,s)
  member x.Bind(State v, f) : State<'s,_> =
    State(fun s ->
      let (a,s) = v s
      let (State v') = f a
      v' s)

let withState<'s> = StateBuilder<'s>()

let getState = State(fun s -> s,s)
let putState v = State(fun _ -> (),v)

let runState (State f) init = f init

's -> 'a * 's中包裹State有什么好处。这只是一种安全预防措施吗?

2 个答案:

答案 0 :(得分:3)

我认为这更多的是偏好或方便而非安全;有些人喜欢将函数包装在一个单例区分的联合类型中,有些人不喜欢。

我不喜欢包装函数,因为它引入了少量的额外开销,并且可能会阻止编译器进行一些优化。在我的ExtCore库中,我实现了相同的功能,使用类型别名而不是创建实际类型来包装函数:

type StateFunc<'State, 'T> = 'State -> 'T * 'State

答案 1 :(得分:2)

我的猜测是包装器来自Haskell传统和可以概括为monad的语言。 在那些laguanges中,您可以使用通用的>>=函数,但每种类型只能有一个实现,有时候会有多个有用的实现。

非常类型的情况就是'a * 'b'a->'b

对于函数'a -> 'b,您可以定义一个读取器,一个状态或解析器monad,告诉哪个实现拾取包装它们的方式,因此它们有不同的类型。

在F#中,事情是不同的,大多数monad库没有定义通用>>=实现,因为在.NET中没有干净的方法来执行此操作,所以没有必要包装State因为你将是明确地应用>>=和其他monad相关函数的具体实现。

如果没有泛型函数或重载,你仍然可以根据需要包装状态monad,但是你必须像在Haskell中一样包装和解包代码,在这种情况下,决定取决于你想要定制多少你的类型是general question,不仅仅是monad。