为什么我不能使用具有存在量化类型的记录选择器?

时间:2012-04-17 13:56:45

标签: haskell record existential-type

使用存在类型时,我们必须使用模式匹配语法来提取forall 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

forall.hs:11:19:
    Cannot use record selector `theA' as a function due to escaped type variables
    Probable fix: use pattern-matching syntax instead
    In the second argument of `($)', namely `theA all'
    In the expression: show $ theA all
    In an equation for `yALL': yALL all = show $ theA all

我的一些数据需要超过5个元素。如果我,很难维护代码 使用模式匹配:

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

是否有一种很好的方法可以使代码可以维护或将其包装起来以便我可以使用某种选择器?

2 个答案:

答案 0 :(得分:18)

存在类型比常规类型更精细地工作。 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不能用作函数的原因。

答案 1 :(得分:16)

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

func1 BigData{ someField = elemx } = func2 elemx

可以工作,并且对于大型类型的输入要少得多。