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