Reputation: 2293
I am currently working on the computation expression series of the fabulous fsharpforfunandprofit website and I have a question regarding the lesson 4 "wrapped type" of the computation series. I have tried reading a bit further , but there's an important notion I am not grasping.
Actually, I do understand the definition of bind :
member Bind : M<'T> * ('T -> M<'U>) -> M<'U>
but one thing I do not understand at this point is the magic when using it in a computation expression with let!:
For instance 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" give me back M<'T> , but custId is already the unwrapped 'T and I cannot see anywhere how does this magic trick work...
Is it part of the code hidden in the let! instruction within Fsharp core assemblies? Could someone explain to me how the let! get the T' out of its wrapper?
Thanks for your explanations
Upvotes: 3
Views: 190
Reputation: 52280
this:
let product'' =
dbresult {
let! custId = getCustomerId "Alice"
let! orderId = getLastOrderForCustomer "" // error!
let! productId = getLastProductForOrder orderId
printfn "Product is %s" productId
return productId
}
will desugar to something like (naming the monad type as 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)))))))
so basically you get a Bind
level for each let!
(you can usually ignore the Delay
)
As you can see the computational expression syntax is much nicer than the nested Binds
- most languages which supports monadic expressions of some sort have similar syntactic sugar - even C# (from ... in ... select
aka LINQ)
Upvotes: 6