Gentle introduction questions / comments

Hi all, I've been reading the gentle introduction to Haskell a bit more closely today and there a few things which I can't quite understand (presumably because they are typo's). I've found two issues with the "Using monads" section [1]. Not sure if this is the right place to report this, but there's probably somewhere here who can fix it :-) The first one is in the state monad data type. It reads: data SM a = SM (S -> (a,S)) -- The monadic type I can't seem to find out what "S" is exactly here. It seems to be a universally quantified type variable, but then it should be lowercase. Considering that it is referred to later on as "s", I suspect this is a type? Further on, a resource monad is described. Here, a lift1 function is given to allow one to lift a normal computation into a resource aware computation, with the following type signature: lift1 :: (a -> b) -> (R a -> R b) A few lines down, the inc operation is defined as follows: inc i = lift1 (i+1) To me, this seems wrong. Even without going into the semantics, it seems that the (i+1) expression does not satisfy the type of the first argument to lift1. I suspect this should have been: inc = lift1 (+1) Gr. Matthijs [1]: http://www.haskell.org/tutorial/monads.html#sect9.3

2009/1/27 Matthijs Kooijman
Hi all,
I've been reading the gentle introduction to Haskell a bit more closely today and there a few things which I can't quite understand (presumably because they are typo's). I've found two issues with the "Using monads" section [1]. Not sure if this is the right place to report this, but there's probably somewhere here who can fix it :-)
The first one is in the state monad data type. It reads:
data SM a = SM (S -> (a,S)) -- The monadic type
I can't seem to find out what "S" is exactly here. It seems to be a universally quantified type variable, but then it should be lowercase. Considering that it is referred to later on as "s", I suspect this is a type?
I guess it's wrong. S should be the type of the state but then it should've been declared as a type variable. I think a more readable declaration could be: data SM s a = SM { runState :: s -> (a,s) }
Further on, a resource monad is described. Here, a lift1 function is given to allow one to lift a normal computation into a resource aware computation, with the following type signature:
lift1 :: (a -> b) -> (R a -> R b)
Mmmmhhh... this seems the signature of the liftM function, whose purpose is to make a function operate on monadic values instead of pure values. Notice that this is different from the "lift" function you described above. A computation is a monadic value (i.e. an object of the type "Monad m => m a") and the "lift" function wraps that value into a monad transformer, making it a new monadic value (i.e. an object of the type "MonadTrans t, Monad m => t m a").
A few lines down, the inc operation is defined as follows:
inc i = lift1 (i+1)
This is clearly wrong, as the expression "i+1" is not of the function type, as required by the signature of lift1 (i.e. a -> b).
To me, this seems wrong. Even without going into the semantics, it seems that the (i+1) expression does not satisfy the type of the first argument to lift1. I suspect this should have been:
inc = lift1 (+1)
You're right. Cristiano

Hi Cristiano,
Mmmmhhh... this seems the signature of the liftM function, whose purpose is to make a function operate on monadic values instead of pure values. Notice that this is different from the "lift" function you described above. A computation is a monadic value (i.e. an object of the type "Monad m => m a") and the "lift" function wraps that value into a monad transformer, making it a new monadic value (i.e. an object of the type "MonadTrans t, Monad m => t m a"). Thanks for clarifying. I don't have my terminology straight yet I guess :-)
Can you fix the issues? Gr. Matthijs

On Tue, Jan 27, 2009 at 3:17 PM, Matthijs Kooijman
Hi Cristiano,
Mmmmhhh... this seems the signature of the liftM function, whose purpose is to make a function operate on monadic values instead of pure values. Notice that this is different from the "lift" function you described above. A computation is a monadic value (i.e. an object of the type "Monad m => m a") and the "lift" function wraps that value into a monad transformer, making it a new monadic value (i.e. an object of the type "MonadTrans t, Monad m => t m a"). Thanks for clarifying. I don't have my terminology straight yet I guess :-)
I hate saying this, as I felt so frustrated when people told me so in the past, but monads and monad transformers are not as difficult as they appear. I advise you to read (and eventually buy) the "Real World Haskell" book instead: I think it's a far superior introduction. Cristiano

2009/1/27 Matthijs Kooijman
Hi all,
I've been reading the gentle introduction to Haskell a bit more closely today and there a few things which I can't quite understand (presumably because they are typo's). I've found two issues with the "Using monads" section [1]. Not sure if this is the right place to report this, but there's probably somewhere here who can fix it :-)
The first one is in the state monad data type. It reads:
data SM a = SM (S -> (a,S)) -- The monadic type
I can't seem to find out what "S" is exactly here. It seems to be a universally quantified type variable, but then it should be lowercase. Considering that it is referred to later on as "s", I suspect this is a type?
Often when working through a concept for the first time, it's simpler to fix particular pieces; in this case, S is some fixed state type. Then, once you get everything working, you notice that you don't make any assumptions about S; then you are free to generalize which lets you universally quantify. Perhaps the tutorial should make this more clear, but this is a process I've gone through with my own code many times; start with the specific and generalize as needed. In addition, type signatures are simpler with as few type variables as possible:
get :: SM S put :: S -> SM ()
as opposed to
get :: SM s s put :: s -> SM s ()
In the state monad case this isn't much of a difference, but I've often found that my code wants three or four additional type variables on a structure. In these cases I do wish for some kind of "parametrized module" syntax, where the module itself is quantified over certain type variables, and the code does not need to explicitly list them everywhere. -- ryan
participants (3)
-
Cristiano Paris
-
Matthijs Kooijman
-
Ryan Ingram