haskell - (Monoid a) 没有因使用“mempty”而产生的实例
问题描述
我有以下代码:
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
,而且它没有办法这样做。
推荐阅读
- python - 如何使用 Pyinstaller 包含需要更改或添加的数据文件和目录?
- redis - Redis 密钥在被读取时会过期吗?
- java - Spring SFTP Adapter InboundAdapter with RotatingServerAdvice - 获取完整路径
- ios - iOS Google Maps SDK 内存管理/内存泄漏
- r - 多个变量的fuzzy_full_join重复R中的列
- ios - 在使用 Swift 的 iOS 应用程序中使用 DispatchQueue 等待数据从 Cloud Firestore 返回时遇到问题
- c# - WPF/XAML - 使用“样式”创建带有模型元素名称的工具提示
- javascript - 从嵌套的 JavaScript 对象中检索属性的最有效方法是什么?
- kubernetes - 在 Kubernetes 部署中创建符号链接
- go - 用一个值替换多个索引