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

Jan*_*ane 0 monads haskell

我试图创建自己的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)’
Run Code Online (Sandbox Code Playgroud)

这是我的代码:

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)
Run Code Online (Sandbox Code Playgroud)

lef*_*out 7

所有实例类型必须是(T a1 ... an)形式

......意思是,你可以写

instance Monad (Writer a) where ...
Run Code Online (Sandbox Code Playgroud)

但不是

instance Monad (Writer String) where ...
Run Code Online (Sandbox Code Playgroud)

因为String它不是一个类型变量.

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

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

或者,您可以使用更多的多态实例,但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)
Run Code Online (Sandbox Code Playgroud)

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