Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/wpf/13.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
混淆Haskell类型推断_Haskell_Polymorphism_Type Inference - Fatal编程技术网

混淆Haskell类型推断

混淆Haskell类型推断,haskell,polymorphism,type-inference,Haskell,Polymorphism,Type Inference,我刚刚开始学习哈斯克尔。由于Haskell是静态类型且具有多态类型推断,因此标识函数的类型为 id :: a -> a 建议id可以将任何类型作为其参数并返回自身。当我尝试以下操作时,效果很好: a = (id 1, id True) 我只是假设在编译时,第一个id是numa::a->a,第二个id是Bool->Bool。当我尝试以下代码时,它给出了一个错误: foo f a b = (f a, f b) result = foo id 1 True 它显示a的类型必须与b的类型相同

我刚刚开始学习哈斯克尔。由于Haskell是静态类型且具有多态类型推断,因此标识函数的类型为

id :: a -> a
建议id可以将任何类型作为其参数并返回自身。当我尝试以下操作时,效果很好:

a = (id 1, id True)
我只是假设在编译时,第一个id是numa::a->a,第二个id是Bool->Bool。当我尝试以下代码时,它给出了一个错误:

foo f a b = (f a, f b)
result = foo id 1 True
它显示a的类型必须与b的类型相同,因为它可以与

result = foo id 1 2

但是id的参数类型可以是多态的,因此a和b可以是不同的类型,这是真的吗?

好吧,这是Haskell类型系统中一个奇怪的阴森角落。这里的问题是,有两种方法可以键入函数
foo

-- rank 1
foo :: forall a b. (a -> b) -> a -> a -> (b, b)
foo f a b = (f a, f b)

-- rank 2
foo' :: (forall a. a -> a) -> a -> b -> (a, b)
foo' f a b = (f a, f b)
第二种类型是你想要的,但第一种类型是你得到的。正如amalloy所指出的,第二种类型是排名2(我们将忽略这两种类型的含义,但如果你想对排名有一个很好的解释,请阅读中的介绍——不要因为PDF文件的学术性质而延迟,因为开头写得易懂且清晰)

我们现在暂缓定义排名较高的类型,只说问题在于GHC无法推断排名2的类型。引述该报:

对于高阶(非指示性)类型系统,完整类型推理是不可判定的,但实际上程序员更愿意添加类型注释来指导类型推理引擎,并记录他们的代码

Kfoury和Wells证明了等级的可类型性是可判定的≤ 2,所有级别都不可判定≥ 3(Kfoury&Wells,1994年)。对于秩-2片段,本文给出了一种类型推断算法。这种推理算法有些微妙,不能与用户提供的类型注释很好地交互,而且据我们所知,还没有在生产编译器中实现

不可判定意味着不可能有算法总是导致正确的是或否决策。因此,你就有了它:不可能推断出一个等级3或更高的类型,而且很难推断出等级2的类型

现在,回到排名2。
(对于所有a.a->a)
是它排名第二的原因。所以我会指给你看,但基本上这意味着你可以在表达式
(fa,fb)
中调用
fa
fb
,而
a
b
是不同类型的,这是你在所有这些混乱之前首先想要的

最后一件事:您通常不会在GHCi中看到
forall
s的原因是,在最外部的作用域上,任何
forall
s都被省略了。所以对于所有的a b。(a->b)->a->a->(b,b)相当于
(a->b)->a->(b,b)

总的来说,这是语言的一个难点,但解释得很差


(在评论中给@amalloy一个小提示。)

这是你想要的吗?@haoformayor不,这是关于所有的
,而不是单态限制,我想。
foo
的推断类型必须是
(对于所有a.a->a)->a->b->(a,b)
,但AFAIK haskell从不推断所有
的类型(我认为称为秩-2类型),即使禁用了单态限制。啊,这就是答案。ghc推断所有a b的秩-1类型
。(a->b)->a->a->(b,b)
,但是你真的想要
(对于所有的a.a->a)->a->b->(a,b)
。我没有时间把这一点具体化为一个答案,但是如果你有时间的话,你可以这样做,@haoformayor。值得注意的是,这两种类型都不比另一种更一般。每一个都可以用另一个不能用的方式。因此,单独使用
foofab=(fa,fb)
对于实际定义的函数是不明确的;目前,通过采用秩-1类型的解释来解决歧义。在一个假设的世界中,GHC有完美的秩-2推理,没有历史包袱,更喜欢秩-1解释,您可能需要添加一些东西来确定选择,因为这不是我们希望编译器为您选择的类型。顺便说一句,类型
。a->a
正好由一个非底部值(
id
)占据,因此
foo'
本质上与
(,)
同构。