3

我目前正在研究 fsharpforfunandprofit 网站的计算表达式系列,我对计算系列的第 4 课“包装类型”有疑问。我已经尝试进一步阅读,但有一个重要的概念我没有掌握。

实际上,我确实了解 bind 的定义:

member Bind : M<'T> * ('T -> M<'U>) -> M<'U>

但在这一点上我不明白的一件事是在 let! 的计算表达式中使用它时的魔力:

例如在:

let product'' = 
    dbresult {
        let! custId = getCustomerId "Alice"
        let! orderId = getLastOrderForCustomer "" // error!
        let! productId = getLastProductForOrder orderId 
        printfn "Product is %s" productId
        return productId
        }
printfn "%A" product''

getCustomerId "Alice"把M<'T>还给我,但custId 已经是未包装的 'T,我在任何地方都看不到这个魔术是如何工作的......

它是隐藏在 let! 中的代码的一部分吗?Fsharp 核心程序集中的指令?有人可以向我解释一下如何让!把 T' 从它的包装里拿出来?

谢谢你的解释

4

1 回答 1

6

这个:

let product'' = 
    dbresult {
        let! custId = getCustomerId "Alice"
        let! orderId = getLastOrderForCustomer "" // error!
        let! productId = getLastProductForOrder orderId 
        printfn "Product is %s" productId
        return productId
        }

脱糖为类似(将 monad 类型命名为 just DB<'t>):

let product'' = 
   DB.Delay(fun () ->
       DB.Bind(getCustomerId "Alice",(fun custId ->
          DB.Bind(getLastOrderForCustomer "",(fun orderId ->
             DB.Bind(getLastProductForOrder orderId, (fun productId ->
                printfn "Product is %s" productId
                DB.Return productId)))))))

所以基本上你会得到一个Bind级别let!(你通常可以忽略Delay

正如您所看到的,计算表达式语法比嵌套的要好得多Binds——大多数支持某种单子表达式的语言都有类似的语法糖——甚至 C#(from ... in ... select又名 LINQ)

于 2015-05-19T09:36:07.827 回答