I've tried to create my own Writer type and afterwards I also made an instance for it. Anyway, I keep on getting this error:
Illegal instance declaration for ‘Monad (Writer String)’
(All instance types must be of the form (T a1 ... an)
where a1 ... an are *distinct type variables*,
and each type variable appears at most once in the instance head.
Use FlexibleInstances if you want to disable this.)
In the instance declaration for ‘Monad (Writer String)’
This is my code:
newtype Writer log a = Writer {runWriter :: (a,log)}
instance Monad (Writer String) where
return a = Writer (a, "")
ma >>= k = let (a, log1) = runWriter ma
(b, log2) = runWriter (k a)
in Writer (b, log1 ++ log2)
All instance types must be of the form (T a1 ... an)
...meaning, you could write
instance Monad (Writer a) where ...
but not
instance Monad (Writer String) where ...
because String is not a type variable.
This is just a silly restriction standard Haskell has had since Haskell98. Apparently, the restriction makes it easier to write a compiler, I don't know. Everybody uses the FlexibleInstances extension, which has been in GHC for ages and disables the restriction.
{-# LANGUAGE FlexibleInstances #-}
newtype Writer log a = Writer {runWriter :: (a,log)}
instance Monad (Writer String) where
...
Alternatively, you could use the more polymorphic instance, but Monad (Writer a) doesn't quite work because you need to be able to have empty logs and concatenate logs. The standard solution is to invoke the generic class for concatenable types:
import Data.Monoid
instance Monoid a => Monad (Writer a) where
return a = Writer (a, mempty)
ma >>= k = let (a, log1) = runWriter ma
(b, log2) = runWriter (k a)
in Writer (b, log1 <> log2)
On another note, to have a Monad instance you must first also instantiate Applicative.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With