I have come across the code below and thought I wanted to rewrite it in order to get a firmer grasp of the Monad. As I have tried to do below. It raises several questions about aspects that I apparently haven't understood fully.
type R = Int
type W = String
type S = Double
newtype RWSP a = RWSP {runRWSP :: R -> S ->
(a, W, S)}
instance Monad RWSP where
return a = RWSP(\_ state -> (a, mempty, state))
m >>= f = RWSP(\r state ->
let (a, w, state') = runRWSP m r state
(a', w', state'') = runRWSP (f a) r state'
in (a', w w', state''))
instance Functor RWSP where
fmap = liftM
instance Applicative RWSP where
pure = return; (<*>) = ap
newtype CustomM a = CustomM {runCustomM :: a -> String}
instance Monad CustomM where
return a = CustomM (\a -> mempty)
m >>= f = CustomM (\a ->
let str = runCustomM m
str' = runCustomM (f a)
in (str' str))
instance Functor CustomM where
fmap = liftM
instance Applicative CustomM where
pure = return; (<*>) = ap
1a. Why is the runRWSP needed in the original example after the let statement. Does this have to do with that a runRWSP takes a monad m, whereas the RWSP is a monad in itself with the type a which requires an anonymous function?
1b. In that case could one go about solving the original code by rewriting it so that no runRWSP was needed but rather a RWSP was used instead?
2a. What about the several nested tuples in the let expression. Why are both important. The f a seems to surround whatever the first runRWSP m r state returns and I guess we can only assume that this monad takes an r and an s due to its newtype definition, is that correctly? When I try to do something similar for the edited version I seem to get an error.
bc. Furthermore I suspect you can use the m
as an argument for runRWSP due to the reverse nature of newtype
like you would with: ghci> CharList "tdada" CharList {getCharList = "tdada"} ghci> getCharList (CharList "something") "something"
at http://learnyouahaskell.com/functors-applicative-functors-and-monoids#the-newtype-keyword
3a. Is it correct to say that the bind operator needs the runRWSP constructor on the right side, because the bind operator has as its output m b
which would require a function whereas the RWSP a
is a monad and not a function and therefore does not change the packed value a
to b
4a. How can I rewrite the monad correctly such that it will compile correctly with the new data type?
CodePudding user response:
Why is the
runRWSP
needed in the original example after the let statement.
It is one of the two available, canonical ways of unwrapping the newtype
wrapper and accessing the chewy nougat inside. The other would be pattern matching; e.g. you could write
let (a, w, state') = case m of RWSP f -> f r state
instead. It would mean the same thing.
Could one go about solving the original code by rewriting it so that no runRWSP was needed but rather a RWSP was used instead?
Yes. See above.
What about the several nested tuples in the let expression. Why are both important?
There are no nested tuples in your code. This one:
let (a, w, state') = runRWSP m r state
is important because:
(a', w', state'') = runRWSP (f a) r state'
^ ^^^^^^
in (a', w w', state''))
^
This one:
(a', w', state'') = runRWSP (f a) r state'
is important because:
in (a', w w', state''))
^^ ^^ ^^^^^^^
The f a seems to surround whatever the first runRWSP m r state returns and I guess we can only assume that this monad takes an r and an s due to its newtype definition, is that correctly?
Sure. I don't love the exact phrasing, but I think what you intended to say here is correct.
Is it correct to say that the bind operator needs the runRWSP constructor on the right side, because the bind operator has as its output
m b
which would require a function whereas theRWSP a
is a monad and not a function and therefore does not change the packed valuea
tob
No, for many reasons. runRWSP
is not a constructor, and it's not needed on the right hand side as described in the first question. m b
usually is not specialized to be a function type, even when Monad m
is floating around in the context somewhere; moreover, in this instance declaration, the m b
that appears in the class declaration has already been specialized to something that is not a function type (namely, RWSP b
). RWSP a
is not a monad; RWSP
(with no application to a
) together with its implementations of fmap
, return
, and (>>=)
is a monad.
How can I rewrite the monad correctly such that it will compile correctly with the new data type?
It cannot be done. Your type parameter appears in a negative position; in any correct Monad
implementation, the type parameter appears only in positive positions.
Or, in less technical (but also less precise) terms: your data type consumes/accepts/absorbs values of its parameter type, whereas monadic values produce/provide/contain values of the parameter type.