使用类型系列,GADT和命名记录编译错误

时间:2017-01-31 13:45:33

标签: haskell gadt type-families

在以下代码中,T1T2编译正常,但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),因此可以在提取这些值时使用这些值。

1 个答案:

答案 0 :(得分:7)

让我们忘记T2T3,然后尝试为T1定义一个提取函数。该类型应该是什么?

x1 :: ???
x1 (T1 a) = a

嗯,你可能会猜到x1 :: T1 (F a) -> a。但那是不对的,如果你尝试一下,那么你将得到与定义T3相同的错误。

问题在于,如果有人向您发送了T1 T,并且您恰好知道类型为AF AT,则您无法得出结论{ {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'

您可以使用模式匹配提取字段(如果有更多字段或约束,则可能很有用),但不能使用记录选择器或函数。