使用存在类型时,我们必须使用模式匹配语法来提取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
是否有一种很好的方法可以使代码可以维护或将其包装起来以便我可以使用某种选择器?
答案 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
可以工作,并且对于大型类型的输入要少得多。