这个问题受到了这个问题的启发。我了解示例(ListBuilder
),但我无法为我的状态单元创建while
循环。我不清楚的是如何 bind
while
循环的主体,因为迭代跟随一个。
谢谢。
/////////////////////////////////////////////////////////////////////////////////////
// Definition of the state
/////////////////////////////////////////////////////////////////////////////////////
type StateFunc<'State, 'T> = 'State -> 'T * 'State
/////////////////////////////////////////////////////////////////////////////////////
// Definition of the State monad
/////////////////////////////////////////////////////////////////////////////////////
type StateMonadBuilder<'State>() =
// M<'T> -> M<'T>
member b.ReturnFrom a : StateFunc<'State, 'T> = a
// 'T -> M<'T>
member b.Return a : StateFunc<'State, 'T> = ( fun s -> a, s)
// M<'T> * ('T -> M<'U>) -> M<'U>
member b.Bind(p : StateFunc<_, 'T>, rest : 'T -> StateFunc<_,_>) : StateFunc<'State, 'U> =
(fun s ->
let a, s' = p s
rest a s')
member b.Zero() = fun s -> (), s
member b.Delay f = f
member b.Run f = f ()
// Getter for the whole state, this type signature is because it passes along the state & returns the state
member b.getState : StateFunc<'State, _> = (fun s -> s, s)
// Setter for the state
member b.putState (s:'State) : StateFunc<'State, _> = (fun _ -> (), s)
// (unit -> bool) * M<'T> -> M<'T>
member b.While (cond, body: StateFunc<'State, _>): StateFunc<'State, _> =
(fun s ->
if cond () then
let bind =
let _, s' = body s
fun s' -> body s'
b.While (cond, bind) // This is wrong
else
body s)
如果您查看ExtCore中的不同计算构建器,请注意一件有趣的事情 - 对于任何单月,While
(以及For
)成员的实现通常相同。/p>
这是因为您始终可以用Bind
,Zero
和While
的递归用途来表达操作。因此,如果您正在使用Monads,您将始终定义这样的内容(只需将M<_>
替换为Monad):
// (unit -> bool) * M<'T> -> M<'T>
member this.While (guard, body : M<_>) : M<_> =
if guard () then
this.Bind (body, (fun () -> this.While (guard, body)))
else
this.Zero ()
对于 all 计算,这不是正确的 - 如果计算在某种程度上更有趣,则可能需要其他While
的实现,但是以上是合理的默认值。
撇开 - 我认为在f#中定义自定义计算表达式的需求应该很少 - 惯用f#代码的使用频率几乎不如例如。Haskell和大多数情况下,您应该对标准库具有的内容(或ExtCore定义的内容,如果您正在做更高级的事情)。也许您需要一个自定义计算,但请记住,这可能是一个分心,导致您朝着错误的方向发展...