Let the mechanics! in calculation expressions
I am currently working on a computation series for an exploit from the fabulous fsharpforfunandprofit website, and I have a question regarding lesson 4 "wrapped type" computation series. I've tried reading a little further, but there is an important concept that I don't understand.
Actually, I understand the definition of bind:
member Bind : M<'T> * ('T -> M<'U>) -> M<'U>
but one thing I don't understand at the moment is the magic when using it in a computation expression with let !:
For example, in:
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" returns M <T> , but custId is already unrolled and I don't see anywhere how this magic trick works ...
Is this part of the code hidden in let! instructions in Fsharp core? Can someone explain to me how they let me in! get T 'out of its wrapper?
Thanks for your explanations.
source to share
let product'' =
dbresult {
let! custId = getCustomerId "Alice"
let! orderId = getLastOrderForCustomer "" // error!
let! productId = getLastProductForOrder orderId
printfn "Product is %s" productId
return productId
}
would desugar for something like (calling the monad type as simple 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)))))))
so basically you get a level Bind
for each let!
(usually you can ignore Delay
)
As you can see, the computational expression syntax is much better than nested Binds
- most languages ββthat support monadic expressions of some kind have similar syntactic sugar - even C # ( from ... in ... select
aka LINQ)
source to share