为什么这种嵌套类型类派生有效?
Why does this nested typeclass derivation work?
是的,这是一个不寻常的“为什么这样做”的问题。
我有这段代码:
{-# LANGUAGE StandaloneDeriving #-}
{-# LANGUAGE QuantifiedConstraints #-}
{-# LANGUAGE UndecidableInstances #-}
data F a = A (F a) | B (a (F a)) -- a :: * -> *
deriving instance (forall b. Eq b => Eq (a b)) => Eq (F a)
-- the following errors, asking me to add (Eq b) into the context
deriving instance (forall b. Eq (a b)) => Eq (F a)
如果一个定义第二个版本出错
data T a = C | D a deriving Eq
x = B C == B C
从逻辑上讲,将(Eq b)
添加到约束中应该是(forall b. Eq b && Eq (a b)) => Eq (F a)
,因为我们需要将其保持在forall
的范围内。可以想象 (Eq b)
是隐式假定的,就像大多数派生实例所做的那样。但如果是这样,为什么第二个版本不起作用?
第一个推导等于以下实例
instance (forall b. Eq b => Eq (f b)) => Eq (F f) where
(==) :: F f -> F f -> Bool
A a1 == A b1 = (==) @(F f) a1 b1
B a1 == B b1 = (==) @(f (F f)) a1 b1
_ == _ = False
鉴于 f (forall b. Eq b => Eq (f b)
) 下的等式是封闭的,(==) @(F f)
和 (==) @(f (F f))
[=25= 需要以下约束]
Eq (F f)
Eq (f (F f))
第一个是我们 writing/deriving 的相等实例:Eq (F f)
在当前上下文中成立(Eq
在 f[=52 下关闭=]).这样就满足了这个约束。
第二个要求我们的提升类型相等:Eq (f (F f))
从上下文中得出:Eq
在 f.[=25 下被关闭=]
如果我们用 F f
实例化 b 我们会看到我们的提升类型支持相等性 Eq (F f) => Eq (f (F f))
如果我们定义的类型支持相等性..做 (1.).
第二个实例在 GHC Head 上编译。
deriving instance (forall b. Eq (f b)) => Eq (F f)
如果你知道 Eq (f b)
对任何 b 成立,你可以解决 1. 和 2. 通过实例化 b 和 F f
.
经过一番尝试,我想我已经解决了这个问题。抱歉经常编辑问题!我把代码简单化了,没有仔细测试
data T a = C | D a
导出需要 Eq a
的 Eq
实例。否则,无法满足 forall b. Eq (T b)
前提。使用 forall b. (Eq b) => Eq (T b)
,我们可以使用 Eq b
来获得 a
.
上所需的相等谓词
是的,这是一个不寻常的“为什么这样做”的问题。 我有这段代码:
{-# LANGUAGE StandaloneDeriving #-}
{-# LANGUAGE QuantifiedConstraints #-}
{-# LANGUAGE UndecidableInstances #-}
data F a = A (F a) | B (a (F a)) -- a :: * -> *
deriving instance (forall b. Eq b => Eq (a b)) => Eq (F a)
-- the following errors, asking me to add (Eq b) into the context
deriving instance (forall b. Eq (a b)) => Eq (F a)
如果一个定义第二个版本出错
data T a = C | D a deriving Eq
x = B C == B C
从逻辑上讲,将(Eq b)
添加到约束中应该是(forall b. Eq b && Eq (a b)) => Eq (F a)
,因为我们需要将其保持在forall
的范围内。可以想象 (Eq b)
是隐式假定的,就像大多数派生实例所做的那样。但如果是这样,为什么第二个版本不起作用?
第一个推导等于以下实例
instance (forall b. Eq b => Eq (f b)) => Eq (F f) where
(==) :: F f -> F f -> Bool
A a1 == A b1 = (==) @(F f) a1 b1
B a1 == B b1 = (==) @(f (F f)) a1 b1
_ == _ = False
鉴于 f (forall b. Eq b => Eq (f b)
) 下的等式是封闭的,(==) @(F f)
和 (==) @(f (F f))
[=25= 需要以下约束]
Eq (F f)
Eq (f (F f))
第一个是我们 writing/deriving 的相等实例:Eq (F f)
在当前上下文中成立(Eq
在 f[=52 下关闭=]).这样就满足了这个约束。
第二个要求我们的提升类型相等:Eq (f (F f))
从上下文中得出:Eq
在 f.[=25 下被关闭=]
如果我们用 F f
实例化 b 我们会看到我们的提升类型支持相等性 Eq (F f) => Eq (f (F f))
如果我们定义的类型支持相等性..做 (1.).
第二个实例在 GHC Head 上编译。
deriving instance (forall b. Eq (f b)) => Eq (F f)
如果你知道 Eq (f b)
对任何 b 成立,你可以解决 1. 和 2. 通过实例化 b 和 F f
.
经过一番尝试,我想我已经解决了这个问题。抱歉经常编辑问题!我把代码简单化了,没有仔细测试
data T a = C | D a
导出需要 Eq a
的 Eq
实例。否则,无法满足 forall b. Eq (T b)
前提。使用 forall b. (Eq b) => Eq (T b)
,我们可以使用 Eq b
来获得 a
.