Reputation: 31
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
:
s
describe the string (password) of the protected data, and a
the type of the protected data?s
describe the type of the protected data, and if so, what does
a
describe?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.
Reader
?Secondly I am having trouble understanding the first line
pd <- lift ask
ask
is used to get access to the shared environment
through the Reader
, but why do I have to lift
it to a MaybeT
to get
the actual value inside of it?Upvotes: 3
Views: 173
Reputation: 116139
As i understand it the Protected type describes some "protected" Data
No. Protected s a
should be seen as the type of a program that returns a value of type a
. During the computation the program has read-only access to a secret value of type s
, and only if it "knows" the proper password.
Such secret value, paired with its password, has type ProtectedData s
.
does s describe the type of the protected Data, and if so, what does a describe?
Yes. Here a
is the, generic, type of the result of the program.
An an example, you can consider the case where the password is a String
(it has to be, in your code the string type is hard-coded) and the secret value has type s = Int
. Then you write a program which accesses the secret integer, and checks whether it's positive, returning a Bool
. Here, a = Bool
.
Note that I simplified the scenario a bit. Since we also use MaybeT
, we are modelling a program that does not always return a value of type a
, but that can also fail. A possible failure could be caused by using the wrong password. In such case, MaybeT
roughly aborts the program in the middle of its execution.
The signature
access :: String -> Protected a a
is perhaps better understood if we write it as
access :: String -> Protected s s
showing that it is a helper function to access the secret value (or failing), given a password attempt. It is used as follows:
myProg :: Protected Int Bool
myProg = do
v <- access "123456" -- try accessing the protected int
return (v > 0)
If the password is wrong, the above code will cause a failure (run
will return Nothing
)
> run (ProtectedData "actual password" 42) myProg
Nothing
If the password is correct, instead it will produce the right boolean:
> run (ProtectedData "123456" 42) myProg
Just True
Here Just
means that the password was correct, and True
indicates that the protected Int
was positive.
Upvotes: 6