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

时间:2018-12-27 11:36:26

标签: haskell monads

我尝试创建自己的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)

1 个答案:

答案 0 :(得分:7)

  

所有实例类型的格式都必须为(T a1 ... an)

...意思是,你可以写

instance Monad (Writer a) where ...

但不是

instance Monad (Writer String) where ...

因为String不是类型变量。

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

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

或者,您可以使用更多多态的实例,但是Monad (Writer a)不能完全正常工作,因为您需要能够具有空日志和连接日志。标准的解决方案是为可连接类型调用通用类:

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)

另一方面,要拥有一个Monad实例,您还必须首先实例化Applicative