Haskell - 构造一个使用存在量化的类型

时间:2015-01-14 15:01:16

标签: haskell existential-type

在下面的代码中,我使用存在量化定义了数据类型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

2 个答案:

答案 0 :(得分:3)

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

不幸的是,我们从未确定a必须是什么!

特别是,GHC通过传入类型C的字典来处理这样的存在,这对应于存在主义中实际结束的任何类型。由于我们从未向GHC提供足够的信息来查找该字典,因此它给我们带来了类型错误。

因此,为了解决这个问题,我们必须在某处实例化C

instance C Int

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

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

答案 1 :(得分:1)

如果您重写下面的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
}