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

时间:2017-06-24 19:29:45

标签: haskell

如果我为import Foundation定义monad转换器类型,则可以派生Identity实例。

Show

将派生

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

但是如果我为instance Show (f a) => Show (IdentityT f a)

定义monad变换器类型
Maybe

我收到错误

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

由于• No instance for (Show (m (Maybe a))) arising from the first field of ‘MaybeT’ (type ‘m (Maybe a)’) 有一个Maybe a个实例,我希望它可以正常工作并推导

Show

为什么不能呢?

2 个答案:

答案 0 :(得分:5)

我认为我们可以通过遵循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)’

好的,Show MaybeT可能不会导致 private TextInputLayout createNewOptionEntry() { View parent = (View) binding.opt1InputLayout.getParent(); FrameLayout.LayoutParams fLayout = (FrameLayout.LayoutParams) parent.getLayoutParams(); TextInputLayout textInputLayout = new TextInputLayout(this); textInputLayout.setLayoutParams(fLayout); textInputLayout.setHint(count++ + ". Option"); LinearLayout.LayoutParams lLayout = new LinearLayout.LayoutParams( LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.WRAP_CONTENT); final TextInputEditText editText = new TextInputEditText(this); editText.setLayoutParams(lLayout); int id = View.generateViewId(); optionsViews.add(id); editText.setId(id); textInputLayout.addView(editText); return textInputLayout; } ,因为这种约束是不允许的,因为它是typechecker无法证明的那种约束终止约。你可以阅读更多关于什么&#34;不小于实例头&#34;在这个答案中意味着:https://stackoverflow.com/a/17866970/176841

答案 1 :(得分:3)

GHC使用启发式方法来确定实例是否保证搜索终止。 通过在此终止,我们的意思是,在搜索实例时,我们不会永远循环。具体而言,这必须是禁止的

instance Show a => Show a where ...

以及

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

GHC大致要求实例上下文中的约束(=>之前的部分)必须小于&#34;更小&#34;比头部的约束(=>之后)。所以,它接受了这个:

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

因为a包含一个小于[a]的类型构造函数。

它也接受这个:

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

因为f a包含一个小于IdentityT f a的类型构造函数。

然而,

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

使用相同数量的构造函数!因此,不能确定它不会导致循环。毕竟,以后,我们可能见面

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

并且很清楚,必须拒绝这两个实例中的至少一个以保证终止。 GHC选择拒绝他们两个。

UndecidableInstances放宽了这个限制。 GHC将接受这两个实例,现在我们要承担避免循环的负担。