这种GADT的使用是否完全等同于存在类型?

时间:2018-03-05 14:31:27

标签: haskell gadt existential-type

Existentially quantified data constructors喜欢

data Foo = forall a. MkFoo a (a -> Bool)
         | Nil

可轻松翻译为GADT:

data Foo where 
    MkFoo :: a -> (a -> Bool) -> Foo
    Nil :: Foo

它们之间是否存在差异:代码与一个而不是另一个编译,或者给出不同的结果?

3 个答案:

答案 0 :(得分:9)

它们几乎相同,尽管不是完全相同,具体取决于你打开的扩展名。

首先,请注意,您无需启用GADTs扩展名即可将data .. where语法用于存在类型。只需启用以下较小的扩展即可。

{-# LANGUAGE GADTSyntax #-}
{-# LANGUAGE ExistentialQuantification #-}

使用这些扩展,您可以编译

data U where
    U :: a -> (a -> String) -> U

foo :: U -> String
foo (U x f) = f x

g x = let h y = const y x
      in  (h True, h 'a')

如果我们用

替换扩展和类型定义,上面的代码也会编译
{-# LANGUAGE ExistentialQuantification #-}
data U = forall a . U a (a -> String)

但是,上面的代码在启用GADTs扩展程序时进行编译!这是因为GADTs也会启用MonoLocalBinds扩展名,这会阻止编译g的上述定义。这是因为后一种扩展会阻止h接收多态类型。

答案 1 :(得分:4)

来自the documentation

  

请注意,GADT样式的语法概括了存在类型(存在量化数据构造函数)。例如,这两个声明是等效的:

data Foo = forall a. MkFoo a (a -> Bool)
data Foo' where { MKFoo :: a -> (a->Bool) -> Foo' }

(强调等同词)

答案 2 :(得分:4)

后者实际上并不是GADT - 它是使用GADT语法声明的存在量化数据类型。因此,它与前者相同。

它不是GADT的原因是没有根据构造函数的选择而改进的类型变量。这是GADT增加的关键新功能。如果您有这样的GADT:

data Foo a where
    StringFoo :: String -> Foo String
    IntFoo :: Int -> Foo Int

然后,每个构造函数上的模式匹配会显示可在匹配子句中使用的其他信息。例如:

deconstructFoo :: Foo a -> a
deconstructFoo (StringFoo s) = "Hello! " ++ s ++ " is a String!"
deconstructFoo (IntFoo i)    = i * 3 + 1

请注意,从类型系统的角度来看,那里发生了一些非常有趣的事情。 deconstructFoo承诺只有a传递Foo a类型的值,才会对{em>任何选择String起作用。但是第一个等式返回Int,第二个等式返回(a ~ String)

这是常规数据类型无法做到的,也是GADT提供的新功能。在第一个等式中,模式匹配将约束(a ~ Int)添加到其上下文中。在第二个等式中,模式匹配会添加export class MyClass { consultationId: string; responseType: { id: string; name: string; }; totalResponses: string; totalNewResponses: string; totalReviewResponses: string; totalCompletedResponses: string; responsesAbstract: { responseId: string; consultationId: string; responseTypeId: string; respondentId: string; responseCurrentStatus: string; }; }

如果您还没有创建一种模式匹配可能导致类型细化的类型,那么您就没有GADT。你只有一个用GADT语法声明的类型。这很好 - 在很多方面,它比基本数据类型语法更好的语法。对于最简单的案例,它只是更加冗长。