Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/haskell/8.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/google-cloud-platform/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Haskell 没有因使用‘;mempty’;_Haskell - Fatal编程技术网

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