我试图实现这个直接Maybe
monad。因此,如果其中一个中间步骤是Nothing
,那么基本上整个表达式的计算结果为Nothing
。
type Maybe<'a> =
| Just of 'a
| Nothing
type MaybeBuilder () =
member this.Combine ((first, second) : Maybe<'a> * Maybe<'b>) : Maybe<'b> =
printfn "Combine called"
match first with
| Nothing -> Nothing
| _ ->
match second with
| Nothing -> Nothing
| _ as a -> a
member this.Zero () = Just ()
member this.Bind((m, f) : Maybe<'a> * ('a -> Maybe<'b>)) =
printfn "Bind called"
match m with
| Nothing -> Nothing
| Just a -> f a
let MaybeMonad = MaybeBuilder()
let foobar =
MaybeMonad {
let! foo = Just "foo"
Just 1
Nothing
}
我希望将foobar
翻译为Just "foo" >>= fun foo -> Combine(Just 1, Nothing)
,但不会调用Combine
。
答案 0 :(得分:7)
这不是计算表达式的编写方式。每次你想要'产生结果'时你需要在表达式的左侧添加一些关键字(return,return!,yield或yield!),在你的例子中我会添加return!
:
let foobar =
MaybeMonad {
let! foo = Just "foo"
return! Just 1
return! Nothing
}
但是你需要将它的定义添加到构建器中:
member this.ReturnFrom (expr) = expr
然后编译器会要求你添加一个Delay方法,在你的情况下我认为你正在寻找类似的东西:
member this.Delay(x) = x()
几乎在那里,现在你有一个值限制,很可能是因为你定义的Combine
在两个参数上都没有使用相同的类型,你可以修复它或只在返回类型中添加一个类型注释:
let foobar : Maybe<int> =
MaybeMonad {
let! foo = Just "foo"
return! Just 1
return! Nothing
}
就是这样,现在你得到了:
Bind called
Combine called
打印并且:
val foobar : Maybe<int> = Nothing
如果您想了解CE的所有细节,请查看这篇好文章:https://www.microsoft.com/en-us/research/publication/the-f-computation-expression-zoo/