0

我已经开始阅读有关计算表达式的内容,据我所知 - 它有一些默认和自定义的隐藏实现。

我会提供我理解的东西并请纠正我。

例如,在这种情况下,我们定义了一个自定义实现来使用 let!。让每一个表情都绑定到让!记录器块内部将记录到控制台。

type LoggingBuilder() =
    let log p = printfn "expression is %A" p

    member this.Bind(x, f) =
        log x
        f x

    member this.Return(x) = x

let logger = new LoggingBuilder()

let loggedWorkflow =
    logger {
        let! x = 42
        let! y = 43
        let! z = x + y
        return z
    }


我记不清了,但我已经读过,如果我们不为其提供实现 - 它有一些内置的默认值。例如,当它收到 None 时,它​​会停止整个工作流并只返回 none,如果它会返回 Some - 代码将继续 -> 这是默认值吗?

由于后跟感叹号的关键字在幕后具有一些额外的功能,那么 async {} 块中的内容是什么?

举这个例子。

let printerAgent =
    MailboxProcessor.Start
        (fun inbox ->

            // the message processing function
            let rec messageLoop () =
                async {

                    // read a message
                    let! msg = inbox.Receive()

                    // process a message
                    printfn "message is: %s" msg

                    // loop to top
                    return! messageLoop ()
                }

            // start the loop
            messageLoop ())

我认为let! msg = inbox.Receive()如果收到 None 将停止工作流。关于退货!我真的不知道。

4

1 回答 1

1

不,计算表达式方法没有默认实现。如果你想要特殊的行为Async<'T option>,你可以添加一个扩展方法到AsyncBuilder. 看起来你想短路 an Async<unit>,所以你会想要这样的东西:

type FSharp.Control.AsyncBuilder with

    member async.Bind(x: Async<'T option>, f: 'T -> Async<unit>) =
        async.Bind(x, function
            | Some x -> f x
            | None -> async.Return())

计算表达式可以解决多个Bind实现之间的重载,但您需要小心:如果类型不明确,F# 将选择在类型本身上实现的方法(在本例中为内置 Bind)而不是扩展方法。

// Here `x` is used as an `int`, so F# knows that it needs to use
// my Bind implementation.
async {
    let! x = myAsyncIntOption
    let y = x + 1
    return ()
}

// Here the type of `x` is unspecified, so F# chooses to use
// the built-in Bind implementation and `x` has type `int option`.
async {
    let! x = myAsyncIntOption
    return ()
}

现在,我已经说了可以做什么,但我不建议实际这样做。相反,我会做一些更明确的事情:

let printerAgent =
    MailboxProcessor.Start
        (fun inbox ->

            // the message processing function
            let rec messageLoop () =
                async {

                    // read a message
                    match! inbox.Receive() with
                    | None -> return ()
                    | Some msg ->

                        // process a message
                        printfn "message is: %s" msg

                        // loop to top
                        return! messageLoop ()
                }

            // start the loop
            messageLoop ())
于 2021-03-19T09:40:52.857 回答