【问题标题】:Why can't I use record selectors with an existentially quantified type?为什么我不能使用存在量化类型的记录选择器?
【发布时间】:2012-04-28 21:03:09
【问题描述】:

当使用 Existential 类型时,我们必须使用模式匹配语法来提取 foralled 值。我们不能将普通的记录选择器用作函数。 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

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

【问题讨论】:

  • 提示:theA 的类型是什么?
  • @Louis Wasserman:你的意思是在 yALL 中使用存在语法吗?怎么样?
  • 基本上,答案是它没有有一个可表达的类型,所以你需要模式匹配来获得一个可行的类型。
  • 或者更准确地说,它应该是 exists a. Show a => ALL -> a 类型,如果 Haskell 拥有一流的存在类型。

标签: haskell record existential-type


【解决方案1】:

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

【讨论】:

  • 通常,您可以将存在类型视为依赖元组,其中第一个元素是类型 (*),第二个元素是该类型的值 - Σ[ a : * ] a。问题是,当您尝试为元组的第二个元素的投影编写类型签名时,您需要知道第一个元素的值。这不能在 Haskell 中表达。如果你有依赖类型的语言,你可以把它写成(使用 Agda 表示法):(x : Σ[ a : * ] a) → fst x.
  • +1 这解释了错误消息“无法使用记录选择器 `theA' 作为函数由于转义类型变量
【解决方案2】:

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

func1 BigData{ someField = elemx } = func2 elemx

有效,并且对于大型类型的输入要少得多。

【讨论】:

  • 很好的答案!后来才发现:data B { x :: Int, y :: Int} ;有趣的 B{..} = x + y;这可以是一个替代方案。
猜你喜欢
  • 2014-10-08
  • 1970-01-01
  • 1970-01-01
  • 2023-04-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-09-27
相关资源
最近更新 更多