Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Illegal instance declaration for 'Monad (Writer String)' [duplicate]

Tags:

haskell

monads

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)
like image 654
Jane-Claire Avatar asked Dec 31 '25 01:12

Jane-Claire


1 Answers

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.

like image 200
leftaroundabout Avatar answered Jan 01 '26 17:01

leftaroundabout



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!