如何在Haskell中为存在类型编写getter

时间:2017-10-30 21:35:34

标签: haskell

感谢this question的回答,我已经定义了类似的类型:

data Chain = forall a. Integral a => Chain [[a]] [a] a a

如果你愿意,我需要为每个字段或参数编写一个getter函数。这是我的第一次尝试:

getSimplices (Chain simplices _ _ _) = simplices

但是当我尝试编译ghc时会出现以下错误:

Chain.hs:10:40: error:
• Couldn't match expected type ‘t’ with actual type ‘[[a]]’
    because type variable ‘a’ would escape its scope
  This (rigid, skolem) type variable is bound by
    a pattern with constructor:
      Chain :: forall a. Integral a => [[a]] -> [a] -> a -> a -> Chain,
    in an equation for ‘getSimplices’
    at Chain.hs:10:15-35
• In the expression: simplices
  In an equation for ‘getSimplices’:
      getSimplices (Chain simplices _ _ _) = simplices
• Relevant bindings include
    simplices :: [[a]] (bound at Chain.hs:10:21)
    getSimplices :: Chain -> t (bound at Chain.hs:10:1)

我这样修好了:

getSimplices (Chain simplices _ _ _) = map (map fromIntegral) simplices

即使某种ghc魔法可以防止这种情况对于吸气者来说非常慢,但我认为以这种方式修复某些东西只是非常残忍。有没有更好的方法来为这样的类型定义getter?

2 个答案:

答案 0 :(得分:8)

存在类型的构造函数必然会忘记"关于a

Chain :: Integral a => [[a]] -> [[a]] -> a -> a -> Chain

请注意结果类型不再取决于a

这样做的结果是,当我们在Chain上进行模式匹配时,我们无法对a是什么做出任何假设。毕竟我们在建造时可以选择任何东西。我们对a的唯一了解是它必须是一个整体类型。因此,我们只能使用Integral类型的方法进行访问。

一般规则是,当我们在Chain上进行模式匹配时,我们必须返回依赖于a的类型的值。像

这样的吸气鬼
getter (Chain _ _ x _) = x

违反了这条规则。毕竟,那会有什么类型?

getter :: Chain -> ???

当然不是

getter :: Chain -> a

这意味着我们可以从Chain中提取任何我们希望的类型。这实际上是行不通的:我们无法自由选择要放入的类型,然后也可以自由选择要取出的类型。

然而,我们可以做的是利用Integral

getter :: Chain -> Integer
getter (Chain _ _ x _) = fromIntegral x

Integer不依赖于a,所以没关系。

答案 1 :(得分:7)

您认为getSimplices应该具有哪种类型? “显而易见”的选择是

getSimplices :: Integral a => Chain -> [[a]]

但这不适用于您的实施,因为getSimplices的来电者可以选择a,并且无法保证Chain中存储的值属于调用者想要的类型,因为你抛弃了那些信息。考虑:

let c = Chain [[1 :: Int]] [2] 3 4
in (getSimplices c) :: [[Integer]]

您的两种类型签名显然允许这样做,它们可以适用于任何Integral类型,但如果没有一些转换,显然也无法工作:Int必须以某种方式转换为Integer

正如评论所说,这是不寻常的。将类型参数添加到Chain会更简单,以便它跟踪用于创建它的类型,并将其输出约束为该类型:

data Chain a = Chain [[a]] [a] a a

getSimplices :: Chain a -> [[a]]
getSimplices (Chain xs _ _ _) = xs