没有使用'mempty'产生(Monoida)的实例
我有以下代码:
data Logger a = Logger { getLog :: (a, [String]) }
instance Functor Logger where
fmap f (Logger (x, log)) = Logger (f x, log)
instance Applicative Logger where
pure x = Logger (x, [])
(Logger (f, log1)) <*> (Logger (x, log2)) = Logger (f x, log1 `mappend` log2)
instance Semigroup a => Semigroup (Logger a) where
(Logger (x, log1)) <> (Logger (y, log2)) = Logger (x <> y, log1 <> log2)
instance Monoid a => Monoid (Logger a) where
mempty = Logger (mempty, [])
instance Monad Logger where
return x = Logger (x, [])
(Logger (x, log)) >>= f = Logger (res, log `mappend` newLog)
where (Logger (res, newLog)) = f x
instance Fail.MonadFail Logger where
fail msg = mempty
我收到以下错误:
• No instance for (Monoid a) arising from a use of ‘mempty’
Possible fix:
add (Monoid a) to the context of
the type signature for:
Fail.fail :: forall a. String -> Logger a
• In the expression: mempty
In an equation for ‘Fail.fail’: Fail.fail msg = mempty
In the instance declaration for ‘Fail.MonadFail Logger’
Monoid a明明说的时候为什么没有实例Monoid a => Monoid (Logger a)?如果我的Logger a类型实例化为Monoid为什么我不能在fail定义中使用 mempty ?我错过了什么?
回答
错误不是抱怨您的Monoid实例。那部分很好。
什么是抱怨是你使用你的定义该实例的MonadFail实例。当你写
fail msg = mempty
然后 GHC 选择Monoid (Logger a)实例。但是该实例对其有一个约束,即Monoid a. 这意味着a必须知道有一个Monoid在这里的地方实例mempty 使用,在这种情况下是你的内部MonadFail实例。
这里的根本问题是它fail有一个非常通用的类型签名:
fail :: forall m a. MonadFail m => String -> m a
请注意,a此处是通用量化的,这意味着允许调用者将其实例化为他们想要的任何类型。这意味着他们可以选择一个Void没有Monoid实例的类型,如 。因此,您的Logger简单类型不能支持MonadFail实例,因为它需要生成一个完全任意类型的值a,而它没有办法这样做。