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