Reputation: 45
I'm a Haskell beginner and I've to solve a worksheet question and this time I'm really stuck. Help!:))
I've to work out the instances for some monad starting with functor up to monad and i can't figure out the pure in the Applicative instance. I don't want to post all the code of the program but I think thoe following should illustrate the problem:
This is given code, can't be changed:
class (Semigroup a, Monoid a) => Log a where
logMsg :: String -> a
newtype Logger l a = Logger (a,l)
deriving Show
logMsgM :: Log l => String -> Logger l ()
logMsgM s = Logger ((), logMsg s)
These are the instances I'm working on:
instance (Log l) => Functor (Logger l) where
fmap g (Logger (a, l)) = Logger ((g a), l)
instance (Log l) => Applicative (Logger l) where
pure ???????????????????
(<*>) (Logger (g,l)) (Logger (a,_)) = Logger ((g a), l)
instance (Log l) => Monad (Logger l) where
return = pure
(>>=) (Logger (a,l)) g = (g a)
(>>) x y = x >>= \_ -> y
With the pure I'm stuck. pure = Logger produces infinte type error a ~ (a,l) and all attempts to tweak with input paranmeters end up in either unknown variable error, or strange type errors with type variables with tailing zeros and such stuff. I tried so much, that's difficult to post the error messages in a more sensible way. I don't undertand what's going on. This is based on a introduction lecture, so I know about the basic concepts. I just can't handle this newtype definition correctly with the function declaration (I think...), in particular this subsumption of two parameters into one (pair). I do understand (or maybe better wording: "I can follow") the typical examples with cases in type defintions or newtypes, such as maybe , either, or other with same number or more parameters at the right side. However, maybe, I'm wrong with this assumption and I'm making a fallacy somewhere I don't see at all.
Btw, the whole code compiles when writing pure = return, but the program produces a stack overflow (smile). I think this is no wonder as return = puer and pure = return may well compile but makes no sense, right!?
Thanx for help :)
Upvotes: 3
Views: 168
Reputation: 8467
Logger
is a type more commonly known as the Writer
monad. The idea is that if you have a Logger l a
, with l
being a Semigroup
, then if you run a Logger l a
and then another Logger l b
, the result will have the two l
s next to each other (i.e. concatenated using the Monoid
operation). That is:
Logger (1,"test1") >> Logger (2,"test2") == Logger (2,"test1" <> "test2")
Given this, pure a
will just be Logger (a, something)
, where something
is a value which doesn’t have any effect when concatenated. But now look at the typeclass declarations:
class (Semigroup a, Monoid a) => Log a where ...
instance (Log l) => Applicative (Logger l) where ...
So in Applicative (Logger l)
, l
must be a Monoid
, so it must have an identity value mempty
! This gives us pure a = Logger (a, mempty)
, which simply returns a
without affecting the log.
However, there is still a problem. If we have Logger (a1,l1) >>= \x -> Logger (a2,l2)
, or Logger (a1,l1) <*> Logger (a2,l2)
, we want to concatenate l1 <> l2
in the result. But your current implementation doesn’t do that! So you’ll need to change it to satisfy this property. Since I don’t want to solve the whole worksheet for you, I’m leaving this as an exercise; however, if you become stuck, you may want to consult the link at the top of this answer.
Upvotes: 6