在以下代码中,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)
,因此可以在提取这些值时使用这些值。
答案 0 :(得分:7)
让我们忘记T2
和T3
,然后尝试为T1
定义一个提取函数。该类型应该是什么?
x1 :: ???
x1 (T1 a) = a
嗯,你可能会猜到x1 :: T1 (F a) -> a
。但那是不对的,如果你尝试一下,那么你将得到与定义T3
相同的错误。
问题在于,如果有人向您发送了T1 T
,并且您恰好知道类型为A
,F A
为T
,则您无法得出结论{ {1}}包含T1 T
类型的值,因为它可以包含另一个A
B
等于F B
的类型T
。作为极端情况,假设我们有
type instance F _ = ()
然后,如果我们猜测x1 :: T1 (F a) -> a
,我们就会
T1 :: a -> T1 ()
x1 :: T1 () -> b
并且编写这些内容会让我们写出a -> b
,这很糟糕。
真实类型的x1
类似于存在主义提供约束
T1 t -> (exists a. (F a ~ t) *> a)
哪个GHC不支持。
T3
的问题实际上与您有
data T3' where T3' :: { x3' :: a } -> T3'
您可以使用模式匹配提取字段(如果有更多字段或约束,则可能很有用),但不能使用记录选择器或函数。