Implementing >>= in newtype

haskell, instance, monads, typeclass

Solution

Let the types guide you. You need

(>>=) :: SnapApp a -> (a -> SnapApp b) -> SnapApp b

You have

(>>=) :: StateT AppState Snap a -> (a -> StateT AppState Snap b) -> StateT AppState Snap b

You need to convert:

- argument `SnapApp a` to `StateT AppState Snap a`

- argument `a -> SnapApp b` to `a -> StateT AppState Snap b`

- result `StateT AppState Snap b` to `SnapApp b`

1) use pattern matching; define:

fromSnapApp (SnapApp x) = x

2) Compose the functions `a -> SnapApp b` and `SnapApp b -> StateT AppState b`

3) Use `SnapApp`

Final result:

x >>= f = SnapApp (fromSnapApp x >>= (fromSnapApp . f)) 

or:

SnapApp x >>= f = SnapApp (x >>= (fromSnapApp . f)) 

You don't have to write this; GHC can derive the instance if you enable the `GeneralizedNewtypeDeriving` extension:

newtype SnapApp a = SnapApp (StateT AppState Snap a) deriving (Monad)

Problem

Let me start from the task I want solve, probably I'm going wrong way. I use Snap framework for toy project, and the main is that it's functions under `Snap` monad. I need to add my state above it. I use monad transformer: ``` type SnapApp a = StateT AppState Snap a ``` This defined in the module, say, `Base`. Since I need it in other modules, I have to export it: ``` module Base ( .. , SnapApp ) where ``` This is good, but I want that module doesn't exported that `SnapApp` is state monad, because I have some complicated processing for setting some attributes for the state. For example, session. I have to write file when it is changed, so it wrong to just `get` and than `put` modified session, special function should be called. So, I hide that using `newtype` and not data exporting construstor: ``` newtype SnapApp a = SnapApp (StateT AppState Snap a) ``` I made it instance of my class with functions for modifying session and etc. But problem arises: I lost instances of `Monad` class and other for new `SnapApp`. And I'm stuck with implementing `>>=`: ``` instance Monad SnapApp where return = SnapApp . return mx >>= fm = -- HOW? ``` Thank you!

Original source