'Monad (Writer String)' 的非法实例声明

Illegal instance declaration for 'Monad (Writer String)'

我尝试创建自己的 Writer 类型,之后我也为它创建了一个实例。不管怎样,我一直收到这个错误:

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)’

这是我的代码:

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)

...意思是,你可以写

instance Monad (Writer a) where ...

但不是

instance Monad (Writer String) where ...

因为String不是类型变量。

这只是 Haskell 自 Haskell98 以来的愚蠢限制标准。显然,该限制使编写编译器变得更容易,我不知道。每个人都使用 FlexibleInstances 扩展,它已经在 GHC 中使用了很长时间并禁用了限制。

{-# LANGUAGE FlexibleInstances #-}
newtype Writer log a = Writer {runWriter :: (a,log)} 
instance Monad (Writer String) where
  ...

或者,您可以使用更多的多态实例,但 Monad (Writer a) 不太有效,因为您需要能够拥有空日志和连接日志。标准解决方案是为可连接类型调用泛型 class:

import Data.Monoid

instance <b>Monoid a =></b> Monad (Writer a) where
  return a = Writer (a, <b>mempty</b>)
  ma >>= k = let (a, log1) = runWriter ma 
                 (b, log2) = runWriter (k a)
             in Writer (b, log1 <b><></b> log2)

另一方面,要获得 Monad 实例,您还必须首先实例化 Applicative