Haskell 没有因使用‘;mempty’;
我有以下代码:Haskell 没有因使用‘;mempty’;,haskell,Haskell,我有以下代码: 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, log
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
为什么当
幺半群a=>幺半群(Logger a)
明确表示时,就没有关于幺半群a
的实例?如果我的记录器a
键入实例化为Monoid
的实例,为什么我不能在失败
定义中使用mempty?我缺少什么?错误并不是抱怨您的Monoid
实例。那部分很好
它抱怨的是您在定义MonadFail
实例时使用了该实例。当你写作时
fail msg = mempty
然后GHC选择Monoid(记录器a)
实例。但该实例有一个约束,即幺半群a
。这意味着必须知道a
在使用mempty
的地方有一个Monoid
实例,在本例中,该实例位于MonadFail
实例中
这里的根本问题是fail
有一个非常通用的类型签名:
fail :: forall m a. MonadFail m => String -> m a
注意这里的
a
是通用量化的,这意味着允许调用方将其实例化为他们想要的任何类型。这意味着他们可以选择像Void
这样的类型,它没有Monoid
实例。因此,您的记录器
简单类型无法支持MonadFail
实例,因为它需要生成一个完全任意类型的值a
,而它无法这样做。Alexis King很好地解释了问题所在。有哪些潜在的解决方案?一种选择是明确包括故障:
data Logger a = Logger
{ theResult :: Either String a
, theLog :: [String] }
现在您可以编写fail m=Logger{theResult=Left m,theLog=[]}
另一个我认为更常见的选择是将日志记录器设置为monad transformer:
您可以使用
Control.Monad.Trans.Writer.Strict
,或者(在许多/大多数情况下更好)来代替自己编写所有内容。谢谢您的解释。谢谢。变压器的解决方案有效。
data Logger a = Logger
{ theResult :: Either String a
, theLog :: [String] }
newtype Logger m a = Logger
{ runLogger :: m (a, [String]) }
instance MonadTrans Logger where
lift m = Logger $ do
a <- m
pure (a, [])
instance MonadFail m => MonadFail (Logger m) where
fail = lift . fail