I'm trying to understand how the Reader monad is used in this blog post as a mechanism to perform functional dependency injection.
The part that confuses me is this bit (taken from the blog post):
Eventually, with this type in hand our simple request handler will be looking like that:
let changePass req = effect {
let! user = Db.fetchUser req.UserId
if user.Hash = bcrypt user.Salt req.OldPass then
let! salt = Random.bytes 32
do! Db.updateUser { user with Salt = salt; Hash = bcrypt salt req.NewPass }
do! Log.info "Changed password for user %i" user.Id
return Ok ()
else
do! Log.error "Password change unauthorized: user %i" user.Id
return Error "Old password is invalid"
}
As you see, there's no more env parameter being passed around. It's now an implicit part of our effect expression
The Effect type is defined as:
[<Struct>] type Effect<'env, 'out> = Effect of ('env -> 'out)
What confuses me is that the implementation of the Reader monad is the same as the one given here (F# for fun and profit) but Scott's example is very clear when it comes to reaching out to environment from within the computation expression (syntactic sugar for monadic operations in f#), while the code above does not make use of ask
at all. See Scott's code:
let readFromConsole() =
reader {
let! (console:IConsole) = Reader.ask
console.WriteLn "Enter the first value"
let str1 = console.ReadLn()
console.WriteLn "Enter the second value"
let str2 = console.ReadLn()
return str1,str2
}
How could one write a function so that the call to Reader monad's ask
function becomes implicit instead of explicit? I could not piece it together from the snippets provided in the first blog post. The accepted answer to this question is also clear about Reader being used with the ask
function.
So is it possible to make the use of ask
implicit?