【问题标题】:Haskell - constructing a type that uses existential quantificationHaskell - 构造一个使用存在量化的类型
【发布时间】:2015-01-14 15:01:16
【问题描述】:

在下面的代码中,我使用存在量化定义了数据类型 F。我希望 F 类型的值保存接受单个参数并产生例如 Int 作为结果的函数。该参数需要实现一个我称之为 C 的类型类,但现在留空。

这是我第一次尝试存在类型。我显然做错了什么,因为我似乎无法创建 F 类型的值。

{-# LANGUAGE ExistentialQuantification #-}

class C a where

data F = forall a. C a => F (a->Int)

makeF :: F
makeF = F $ const 1

如何解决这个编译错误?

No instance for (C a0) arising from a use of `F'
In the expression: F
In the expression: F $ const 1
In an equation for `makeF': makeF = F $ const 1

【问题讨论】:

  • 我发现使用 GADT 更容易完成这类事情。你可以有存在量化和类约束,但语法要简洁得多。
  • 感谢您的提示。我也应该阅读 GADT。

标签: haskell existential-type


【解决方案1】:

问题在于const 1 的类型为forall a . C a => a -> Int。当您将其传递给 F 时,我们将失去再次讨论 a 类型的机会,除非它是 C 类型的元素。

很遗憾,我们从未确定a 必须是什么!

特别是,GHC 通过为类型类 C 传入 dictionary 来处理此类存在,该类型类 C 对应于实际最终出现在存在中的任何类型。由于我们从未向 GHC 提供足够的信息来查找该字典,因此它给了我们一个类型错误。

所以要解决这个问题,我们必须在某处实例化 C

instance C Int

然后传递一个函数,该函数确定被遗忘的类型a实际上是C的一个实例

let x = F (const 1 :: Int -> Int)

【讨论】:

  • 感谢您的解释。这让我对正在发生的事情有更直观的感觉。似乎存在类型并不是我真正想要的。我需要能够在不知道实现 C 的具体类型是什么的情况下组合我的 F 来创建新的 F。
  • @knick 编译器不知道具体类型是什么重要吗?我问你的使用场景是否可以使用多态而不是存在类型。
【解决方案2】:

如果你重写你的F 定义,它会起作用:

{-# LANGUAGE RankNTypes #-}

class C a where

data F = F (forall a. C a => a -> Int)

makeF :: F
makeF = F $ const 1

我正在尝试自己理解为什么:

您的原始类型说“存在a,它是C 的实例,我们有函数a -> Int”。 所以要构造存在类型,我们必须说明我们有哪个a

{-# LANGUAGE ExistentialQuantification #-}

class C a where

data F = forall a. C a => F (a -> Int)

-- Implement class for Unit
instance C () where

makeF :: F
makeF = F $ (const 1 :: () -> Int)

这些定义并不完全相同:

data G = forall a . C a => G {
  value :: a         -- is a value! could be e.g. `1` or `()`
  toInt :: a -> Int, -- Might be `id`
}

data G' = G' {
  value' :: C a => a          -- will be something for every type of instance `C`
  toInt' :: C a => a -> Int, -- again, by parametericity uses only `C` stuff
}

【讨论】:

  • 太好了,我的代码现在可以编译了 :) 感谢您的解释。
  • 我稍微修改了答案。 RankNTypeExistentialQuantification 方法之间存在细微差别。
  • 两个版本差别不大,差别很大。在一个变量中,变量在另一个中被普遍量化。它对您如何使用该功能产生了巨大的影响。
  • @augustss,您是否有一个用例,其中一种方法有效而另一种方法几乎是不可能的?例如。对于24 days of GHC extensions 示例,这两种方法都同样有效吗?
  • @Oleg 我正在打电话,所以我的回复会很短。使用通用量化,在模式匹配之后,您可以使用您选择的类型的函数(如果需要,可以使用许多不同的类型)。存在量化,模式匹配后的类型变量有一个固定的类型,但你不知道是哪一个;它表现为抽象类型。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-12-27
  • 2023-04-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多