简体   繁体   English

为什么不能为MaybeT派生Show实例?

[英]Why can't the Show instance be derived for MaybeT?

If I define the monad transformer type for Identity , it is able to derive the Show instance. 如果我为Identity定义monad转换器类型,它可以派生Show实例。

newtype IdentityT f a =
  IdentityT { runIdentityT :: f a }
  deriving (Show)

will derive 将衍生出来

instance Show (f a) => Show (IdentityT f a)

But if I define the monad transformer type for Maybe 但是如果我为Maybe定义monad变换器类型

newtype MaybeT m a =
  MaybeT { runMaybeT :: m (Maybe a) }
  deriving (Show)

I get the error 我收到了错误

• No instance for (Show (m (Maybe a)))
        arising from the first field of ‘MaybeT’ (type ‘m (Maybe a)’)

Since Maybe a has a Show instance, I would expect it to work and derive 由于Maybe a有一个Show实例,我希望它可以工作并派生出来

instance Show (m (Maybe a)) => Show (MaybeT m a)

Why can't it? 为什么不能呢?

I think we can see the issue by following GHC's suggestions (I'm using 8.2.1) until we hit a dead end: 我想我们可以通过遵循GHC的建议(我正在使用8.2.1)看到这个问题,直到我们走到尽头:

Prelude> :{
Prelude| newtype MaybeT m a =
Prelude|   MaybeT { runMaybeT :: m (Maybe a) }
Prelude|   deriving (Show)
Prelude| :}

<interactive>:12:13: error:
    • No instance for (Show (m (Maybe a)))
        arising from the first field of ‘MaybeT’ (type ‘m (Maybe a)’)
      Possible fix:
        use a standalone 'deriving instance' declaration,
          so you can specify the instance context yourself
    • When deriving the instance for (Show (MaybeT m a))
Prelude> :set -XStandaloneDeriving 
Prelude> deriving instance Show (m (Maybe a)) =>  Show (MaybeT m a)

<interactive>:17:19: error:
    • The constraint ‘Show (m (Maybe a))’
        is no smaller than the instance head
      (Use UndecidableInstances to permit this)
    • In the stand-alone deriving instance for
        ‘Show (m (Maybe a)) => Show (MaybeT m a)’

Okay, so Show wasn't derivable for MaybeT likely because that constraint would have been disallowed, as it's the sort of constraint the typechecker can't prove termination about. 好的,所以Show可能不会导致MaybeT因为这种约束是不允许的,因为它是类型检查器无法证明终止的约束。 You can read more about what "no smaller than instance head" means in this answer: https://stackoverflow.com/a/17866970/176841 您可以在此答案中详细了解“不小于实例头”的含义: https//stackoverflow.com/a/17866970/176841

GHC uses a heuristics to determine if an instance guarantees search termination. GHC使用启发式方法来确定实例是否保证搜索终止。 By termination here, we mean that, when searching for an instance we will not loop forever. 通过在此终止,我们的意思是,在搜索实例时,我们不会永远循环。 Concretely,this must be forbidden 具体而言,必须禁止这样做

instance Show a => Show a where ...

as well as this 以及这个

instance Show [a] => Show a where ...

GHC roughly requires that constraints in the instance context (the part before the => ) must be "smaller" than the constraint in the head (after the => ). GHC粗略地要求实例上下文中的约束( =>之前的部分)必须比头部中的约束“更小”(在=> )。 So, it accepts this: 所以,它接受这个:

instance Show a => Show [a] where ...

since a contains one type constructor less than [a] . 因为a包含一个小于[a]类型构造函数。

It also accepts this: 它也接受这个:

instance Show (f a) => Show (IdentityT f a) where ...

since fa contains one type constructor less than IdentityT fa . 因为fa包含一个小于IdentityT fa类型构造函数。

However, 然而,

instance Show (f (Maybe a)) => Show (MaybeT f a) where ...

uses the same number of constructors! 使用相同数量的构造函数! Hence, it is not accepted to be sure it will not cause a loop. 因此,不能确定它不会导致循环。 After all, later on, we might meet 毕竟,以后,我们可能会见面

instance Show (MaybeT f a)) => Show (f (Maybe a)) where ...

and it's clear that at least one of these two instances must be rejected to guarantee termination. 并且很明显,必须拒绝这两个实例中的至少一个以保证终止。 GHC chooses to reject both of them. GHC选择拒绝他们两个。

UndecidableInstances relaxes this restriction. UndecidableInstances放宽了这个限制。 GHC will accept both instances, and now the burden is on us to avoid loops. GHC将接受这两个实例,现在我们要承担避免循环的负担。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM