【问题标题】:F# computation expression when is Combine called调用组合时的 F# 计算表达式
【发布时间】:2017-05-16 03:32:07
【问题描述】:

我试图直接实现这个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" &gt;&gt;= fun foo -&gt; Combine(Just 1, Nothing),但是Combine 没有被调用。

【问题讨论】:

    标签: f# monads


    【解决方案1】:

    这不是计算表达式的预期编写方式。每次您想要“产生结果”时,您都需要在表达式的左侧添加一些关键字(return、return!、yield 或 yield!),在您的示例中,我将添加一个 return!

    let foobar =
        MaybeMonad {
            let! foo = Just "foo"
            return! Just 1
            return! Nothing
        }
    

    但是你需要将它的定义添加到构建器中:

    member this.ReturnFrom (expr) = expr
    

    然后编译器会要求你添加一个延迟方法,在你的情况下,我认为你正在寻找类似的东西:

    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/

    【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多