I was hoping to get some helpful input on understanding Monad Transformers, and in relation to that, what happens using do notation. The example I am trying to understand is the following:
data ProtectedData a = ProtectedData String a
accessData :: String -> ProtectedData a -> Maybe a
accessData s (ProtectedData pass v) =
if s == pass then Just v else Nothing
type Protected s a = MaybeT (Reader (ProtectedData s)) a
-- untangles the monad construction
run :: ProtectedData s -> Protected s a -> Maybe a
run ps psa = runReader (runMaybeT psa) ps
access :: String -> Protected a a
access pass = do
-- ask :: ReaderT (ProtectedData a) Identity (ProtectedData a)
-- lift :: ... -> MaybeT (ReaderT (ProtectedData a) Identity) (ProtectedData a)
pd <- lift ask
-- as i understand it: ask returns the value inside the thing.
-- the left arrow actually applies the monad
let v = accessData pass pd
-- return :: Maybe a -> Reader (ProtectedData a) (Maybe a)
MaybeT $ return v
As I understand it the Protected type describes some protected data, that is stored in a shared environment (Reader) and is of type Maybe (MaybeT).
I am having problems with the type-variables s and a:
- Does
sdescribe the string (password) of the protected data, andathe type of the protected data? - Does
sdescribe the type of the protected data, and if so, what doesadescribe?
In the function run:
run :: ProtectedData s -> Protected s a -> Maybe a
run ps psa = runReader (runMaybeT psa) ps
As I understand it, the Reader from inside Protected is run on the ProtectedData, to return the value.
This leaves only the function access:
access :: String -> Protected a a
access pass = do
pd <- lift ask
let v = accessData pass pd
MaybeT $ return v
Which is the one providing the most headache for me. First I am having issues grasping the effect and result.
- Is this function used to inject passwords and data into the
Reader? - Is it used to access data and fail if the wrong password is given?
Secondly I am having trouble understanding the first line
pd <- lift ask
- I understand, that
askis used to get access to the shared environment through theReader, but why do I have toliftit to aMaybeTto get the actual value inside of it?