Haskell 为什么可以';我是否使用具有存在量化类型的记录选择器?

Haskell 为什么可以';我是否使用具有存在量化类型的记录选择器?,haskell,record,existential-type,Haskell,Record,Existential Type,当使用存在类型时,我们必须使用模式匹配语法来提取for alled值。我们不能使用普通的记录选择器作为函数。GHC报告了一个错误,并建议使用模式匹配来定义yALL: {-# LANGUAGE ExistentialQuantification #-} data ALL = forall a. Show a => ALL { theA :: a } -- data ok xALL :: ALL -> String xALL (ALL a) = show a -- pattern m

当使用存在类型时,我们必须使用模式匹配语法来提取
for all
ed值。我们不能使用普通的记录选择器作为函数。GHC报告了一个错误,并建议使用模式匹配来定义
yALL

{-# LANGUAGE ExistentialQuantification #-}

data ALL = forall a. Show a => ALL { theA :: a }
-- data ok

xALL :: ALL -> String
xALL (ALL a) = show a
-- pattern matching ok

-- ABOVE: heaven
-- BELOW: hell

yALL :: ALL -> String
yALL all = show $ theA all
-- record selector failed

我的一些数据包含5个以上的元素。如果我 使用模式匹配:

func1 (BigData _ _ _ _ elemx _ _) = func2 elemx

有没有一种好方法可以让这样的代码保持可维护,或者将其包装起来,以便我可以使用某种选择器?

您可以在模式匹配中使用记录语法

func1 BigData{ someField = elemx } = func2 elemx

大型类型的工作方式和类型要少得多。

存在类型的工作方式比常规类型更加复杂。GHC(正确地)禁止您将
theA
用作函数。但是想象一下,没有这样的禁令。该函数将具有什么类型?必须是这样的:

-- Not a real type signature!
theA :: ALL -> t  -- for a fresh type t on each use of theA; t is an instance of Show
简而言之,
forall
使GHC“忘记”构造函数参数的类型;类型系统只知道该类型是
Show
的一个实例。因此,当您试图提取构造函数参数的值时,无法恢复原始类型

GHC在幕后所做的是,每当您对
ALL
构造函数进行模式匹配时,上面对伪类型签名的注释所说的,绑定到构造函数值的变量被分配一个唯一的类型,该类型保证与其他类型不同。以该代码为例:

case ALL "foo" of
    ALL x -> show x

变量
x
获取一个唯一的类型,该类型不同于程序中的所有其他类型,并且不能与任何类型变量匹配。这些独特的类型不允许转义到顶层,这就是为什么
theA
不能用作函数的原因。

提示:
theA
的类型是什么?@Louis Wasserman:你的意思是在yALL中使用存在语法吗?怎么做?基本上,答案是它没有一个可表达的类型,所以你需要模式匹配来获得一个可行的类型。或者更准确地说,它会有一个类型
exists a。Show a=>ALL->a
,Haskell拥有一流的存在类型。通常,您可以将存在类型视为依赖元组,其中第一个元素是类型(
*
),第二个元素是该类型的值-
∑[a:]a
。问题是,当您试图为元组的第二个元素的投影编写类型签名时,您需要知道第一个元素的值。这不能用Haskell表示。如果您有依赖类型的语言,您可以将其编写为(使用Agda表示法):
(x:∑[a:]a)→ fst x
+1这解释了错误消息“由于转义类型变量,无法将记录选择器'theA'用作函数”的原因。回答得很好!我后来才找到它:数据B{x::Int,y::Int};乐趣B{..}=x+y;这可能是另一种选择。
case ALL "foo" of
    ALL x -> show x