类型族、GADT 和命名记录的编译错误
Compile error with type families, GADTs and named records
在下面的代码中,T1
和 T2
编译正常,但 T3
失败:
{-# LANGUAGE GADTs #-}
{-# LANGUAGE TypeFamilies #-}
type family F a
data T1 b where
T1 :: a -> T1 (F a)
data T2 b where
T2 :: { x2 :: a } -> T2 a
data T3 b where
T3 :: { x3 :: a } -> T3 (F a)
我正在尝试了解原因。 T3
只是 T1
但有一个命名记录。这似乎并没有那么特别,因为无论如何都可以使用构造函数语法来提取它。
这些例子可能看起来很傻,但在我的代码中有对 a
的约束,例如(Show a)
,因此这些值可以在提取时使用。
让我们忘记 T2
和 T3
,并尝试为 T1
定义一个提取函数。类型应该是什么?
x1 :: ???
x1 (T1 a) = a
嗯,你可能会猜到 x1 :: T1 (F a) -> a
。但这是不对的,如果您尝试这样做,您将得到与定义 T3
.
相同的错误
问题是,如果有人给你一个 T1 T
,而你碰巧知道一个类型 A
,使得 F A
是 T
,你不能得出结论T1 T
包含类型 A
的值,因为它可以包含另一个类型 B
,其中 F B
等于 T
。作为极端情况,假设我们有
type instance F _ = ()
然后如果我们按照我们的猜测 x1 :: T1 (F a) -> a
,我们将有
T1 :: a -> T1 ()
x1 :: T1 () -> b
并且组合这些会让我们写出 a -> b
,这很糟糕。
x1
的真实类型类似于 existential-providing-constraint
T1 t -> (exists a. (F a ~ t) *> a)
哪个 GHC 不支持。
T3
的问题实际上与
的问题相同
data T3' where T3' :: { x3' :: a } -> T3'
您可以使用模式匹配提取字段(如果有更多字段或约束,这可能会有用),但不能使用记录选择器或函数。
在下面的代码中,T1
和 T2
编译正常,但 T3
失败:
{-# LANGUAGE GADTs #-}
{-# LANGUAGE TypeFamilies #-}
type family F a
data T1 b where
T1 :: a -> T1 (F a)
data T2 b where
T2 :: { x2 :: a } -> T2 a
data T3 b where
T3 :: { x3 :: a } -> T3 (F a)
我正在尝试了解原因。 T3
只是 T1
但有一个命名记录。这似乎并没有那么特别,因为无论如何都可以使用构造函数语法来提取它。
这些例子可能看起来很傻,但在我的代码中有对 a
的约束,例如(Show a)
,因此这些值可以在提取时使用。
让我们忘记 T2
和 T3
,并尝试为 T1
定义一个提取函数。类型应该是什么?
x1 :: ???
x1 (T1 a) = a
嗯,你可能会猜到 x1 :: T1 (F a) -> a
。但这是不对的,如果您尝试这样做,您将得到与定义 T3
.
问题是,如果有人给你一个 T1 T
,而你碰巧知道一个类型 A
,使得 F A
是 T
,你不能得出结论T1 T
包含类型 A
的值,因为它可以包含另一个类型 B
,其中 F B
等于 T
。作为极端情况,假设我们有
type instance F _ = ()
然后如果我们按照我们的猜测 x1 :: T1 (F a) -> a
,我们将有
T1 :: a -> T1 ()
x1 :: T1 () -> b
并且组合这些会让我们写出 a -> b
,这很糟糕。
x1
的真实类型类似于 existential-providing-constraint
T1 t -> (exists a. (F a ~ t) *> a)
哪个 GHC 不支持。
T3
的问题实际上与
data T3' where T3' :: { x3' :: a } -> T3'
您可以使用模式匹配提取字段(如果有更多字段或约束,这可能会有用),但不能使用记录选择器或函数。