![](/img/trans.png)
[英]Why can't GHC typecheck this function involving polymorphism and existential types?
[英]Why does GHC refuse to allow this existential type function?
我已经定义了一个通用的heterogenous ,我称之为(我不知道这是否正确),输入:
data Heterotype f = forall a. f a => Heterotype a
然后我决定创建一个函数,允许您从多态值创建异型:
hset :: (forall a. f a => a) -> Heterotype f
hset x = Heterotype x
但是,GHC 抱怨以下内容:
████████.hs:15:10: error:
* Could not deduce: f a0 arising from a use of `Heterotype'
* In the expression: Heterotype x
In an equation for `hset': hset x = Heterotype x
* Relevant bindings include
x :: forall a. f a => a
(bound at ████████.hs:15:6)
hset :: (forall a. f a => a) -> Heterotype f
(bound at ████████.hs:15:1)
|
15 | hset x = Heterotype x
| ^^^^^^^^^^^^
编辑:启用以下扩展:
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE GADTs, ScopedTypeVariables #-}
{-# LANGUAGE NoStarIsType, ConstraintKinds #-}
{-# LANGUAGE AllowAmbiguousTypes, RankNTypes #-}
import Data.Kind
从逻辑的角度来看,您的代码将对应于逻辑公式的证明,可以如下(粗略地)阅读:
f
是任何类型的属性;f
任何类型a
,我们可以产生类型a
的值x
;f
且值为x
的类型a
。 这在逻辑上是不合理的。 事实上,无论a
是什么, fa
都可能永远不成立。 在这种情况下,上面的假设空洞地成立,因此它是正确的。 然而,上述结论与fa
总是错误的事实相矛盾。
因此,我们无法使用该类型定义您的hset
。
为了使论证合理,我们必须添加一个额外的假设,即存在某种类型b
使属性f
真。 如果我们加上这个假设,我们可以证明这个陈述:
-- (untested, but should work)
hset :: forall b . f b => (forall a. f a => a) -> Heterotype f
hset x = Heterotype (x :: b)
您的数据定义隐藏的monotyped选择a
被包装起来,从词典的价值f
。 重要的是要认识到,这样做的全部意义在于丢弃有关特定类型的信息,同时保留与该类型关联的实例字典。
这与您在hset
尝试执行的操作不hset
。 从来没有一个具体的类型来打包实例。 这些部分不能以这种方式组合在一起,因为它们都缺少相同的必需的东西。 Heterotype f
和(forall a. fa => a)
都缺乏一个具体的类型来选择一个实例,但是Heterotype
构造器需要一个具体的实例来包含。 只是信息不存在。 这些部分是不兼容的。
您有点过度指定了:),以下工作正常:
data Heterotype f = forall a. f a => Heterotype a
hset :: forall f a. f a => a -> Heterotype f
hset x = Heterotype x
不同之处在于您已经量化了您的参数: (forall a. fa => a)
表示此函数接受一个表达式,该表达式必须同时是任何可能的类型(调用者不能选择特定的“a”) ,这真的没有意义。 新版本(因此是相同的只是用Heterotype
自身的构造函数)说,来电者被允许挑选的类型a
,它可以是任何东西,但必须只有一个类型(一次有效)。
习惯存在主义可能需要一些练习; 最好的方法是反复试验:)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.