我目前正致力于神话般的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&lt;'T&gt; ,但 custId 已经是解开的'T 强大的>我无法看到这个神奇的技巧如何发挥作用......
它是隐藏在let中的代码的一部分! Fsharp核心组件内的指令?有人可以向我解释这是怎么回事!把T'从包装中拿出来?
感谢您的解释
答案 0 :(得分:6)
这样:
let product'' =
dbresult {
let! custId = getCustomerId "Alice"
let! orderId = getLastOrderForCustomer "" // error!
let! productId = getLastProductForOrder orderId
printfn "Product is %s" productId
return productId
}
将 desugar 改为(将monad类型命名为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
更好 - 大多数支持某种monadic表达式的语言具有类似的语法糖 - 甚至是C#(from ... in ... select
又名LINQ)