views:

197

answers:

2

After reading (and skimming some sections of) Wadler's paper on monads, I decided to work through the paper more closely, defining functor and applicative instances for each of the monads he describes. Using the type synonym

type M a = State -> (a, State)
type State = Int

Wadler uses to define the state monad, I have the following (using related names so I can define them with a newtype declaration later on).

fmap' :: (a -> b) -> M a -> M b
fmap' f m = \st -> let (a, s) = m st in (f a, s)

pure' :: a -> M a
pure' a = \st -> (a, st)

(<@>) :: M (a -> b) -> M a -> M b
sf <@> sv = \st -> let (f, st1) = sf st
                       (a, st2) = sv st1
                    in (f a, st2)

return' :: a -> M a
return' a = pure' a

bind :: M a -> (a -> M b) -> M b
m `bind` f = \st -> let (a, st1) = m st
                        (b, st2) = f a st1
                     in (b, st2)

When I switch to using a type constructor in a newtype declaration, e.g.,

newtype S a = S (State -> (a, State))

everything falls apart. Everything is just a slight modification, for instance,

instance Functor S where
 fmap f (S m) = S (\st -> let (a, s) = m st in (f a, s)) 

instance Applicative S where
 pure a = S (\st -> (a, st))

however nothing runs in GHC due to the fact that the lambda expression is hidden inside that type constructor. Now the only solution I see is to define a function:

isntThisAnnoying s (S m) = m s

in order to bind s to 'st' and actually return a value, e.g.,

fmap f m = S (\st -> let (a, s) = isntThisAnnoying st m in (f a, s))

Is there another way to do this that doesn't use these auxiliary functions?

+6  A: 

If you look here, you will see that they define it this way:

newtype State s a = State { runState :: (s -> (a,s)) }

so as to give the inner lambda a name.

Daniel Pratt
Which also means `runState = flip isntThisAnnoying`.
KennyTM
Okay - so while an auxiliary function is still needed, I could just define the type using a record, getting the function for free. What you're saying, then, is that there is no way to avoid using functions like 'runState' or 'run'. Thanks.
danportin
If it hurts you to think of it as a function, think of it as a struct field accessor instead. :-)
Owen S.
Oh, well it doesn't hurt me. I was just wondering if there was a better way to define it. As you pointed out, 'runState' is perfectly fine :) But Haskell is my first language, so I'd rather think of it as a function from s to (a, s), because that's what it is.
danportin
+2  A: 

The usual way is to define newtype newtype S a = S {runState : State -> (a, State)}. Then instead of your isntThisAnnoying s (S m) you can write runState t s where t is the same as S m.
You have to use a newtype because type synonyms cannot be typeclass instances.

Daniel Velkov