Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/haskell/10.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 为什么GHC在这里推断出单态类型,即使禁用了单态限制?_Haskell_Recursion_Type Inference_Parametric Polymorphism - Fatal编程技术网

Haskell 为什么GHC在这里推断出单态类型,即使禁用了单态限制?

Haskell 为什么GHC在这里推断出单态类型,即使禁用了单态限制?,haskell,recursion,type-inference,parametric-polymorphism,Haskell,Recursion,Type Inference,Parametric Polymorphism,这是由,它讨论了一个更复杂的例子,但这一个也适用 以下定义编译时没有问题: w :: Integral a => a w = fromInteger w …当然它在运行时不起作用,但这与问题无关。关键是w本身的定义使用了w::Integer的专门版本。显然,这是一个合适的实例化,因此需要进行类型检查 但是,如果我们删除签名,那么GHC推断的不是上述类型,而是具体类型: w' = fromInteger w' 当我看到这个的时候,我很确定这就是工作中的单态限制。众所周知,也有 i = 3

这是由,它讨论了一个更复杂的例子,但这一个也适用

以下定义编译时没有问题:

w :: Integral a => a
w = fromInteger w
…当然它在运行时不起作用,但这与问题无关。关键是
w
本身的定义使用了
w::Integer
的专门版本。显然,这是一个合适的实例化,因此需要进行类型检查

但是,如果我们删除签名,那么GHC推断的不是上述类型,而是具体类型:

w' = fromInteger w'
当我看到这个的时候,我很确定这就是工作中的单态限制。众所周知,也有

i = 3
尽管
i::nump=>p
是完全可能的。事实上,如果
-XNoMonomorphismRestriction
处于活动状态,即如果禁用单态限制,则推断出
i::Num p=>p

但是,在
w'
的情况下,即使禁用了单态限制,也只会推断出类型
Integer

要计算出这与默认有关,请执行以下操作:

fromFloat :: RealFrac a => Float -> a
q :: RealFrac a => a
q = fromFloat q
q' = fromFloat q'
为什么不推断多态类型?

多态递归(函数以不同于调用它的类型的类型调用自己)始终需要类型签名。哈斯凯尔2010年报告的全文如下:

如果定义变量
f
时未提供相应的类型签名声明,则在其自己的声明组(请参阅)之外的
f
的每次使用都被视为具有相应的推断类型或主体类型。但是,为了确保类型推断仍然是可能的,定义事件及其声明组中的
f
的所有使用必须具有相同的单态类型(如中所述,主要类型是通过泛化获得的)

后面的同一节给出了一个类型签名支持的多态递归示例

我的理解是,在存在多态递归的情况下,独立类型推理通常是不可判定的,因此Haskell甚至没有尝试

在这种情况下,类型检查器以

w :: a
其中
a
是元变量。由于
fromInteger
在其自身声明中(因此在其声明组中)作为参数使用
w
调用,因此类型检查器将
a
Integer
统一起来。没有可以概括的变量了

出于同样的原因,对程序稍作修改会产生不同的结果:

v = fromIntegral v
根据您最初的推理,Haskell会推断出所有a。Num a=>a,将RHS上的
v
默认为键入
整数

v :: forall a. Num a => a
v = fromIntegral (v :: Integer)
但是,它以
v::a
开头。由于
v
从Integral传递到
,因此它强制执行
积分a
。最后,它概括了
a
。最后,这个程序被证明是正确的

v :: forall a. Integral a => a
v = fromIntegral (v :: a)

单态限制不是只适用于简单绑定吗(而且递归的
w'=fromInteger w'
,并不简单)?@Alec可能,但仍然–为什么像单态限制这样的东西似乎在这里起作用?我可能很密集,这里缺少一些东西,但是
fromInteger
有类型
(Num a)=>Integer->a
,而且由于
w'
被用作
fromInteger
的输入,这难道不意味着
Integer
是它唯一可能的类型吗?事实上,我对具有多态类型签名的版本能够编译感到相当惊讶。(正如我所说,可能遗漏了一些东西。)@RobinZigmond
Integer
无疑是
w'
唯一可能的单态类型,但正如
w
所证明的那样,多态类型也很好。毕竟,多态类型可以实例化为单态类型,只要它满足约束条件。我的学士学位是关于一个简单的su类型推断器B Haskell的集合,包括类型类和多态递归。一个非常简单的方法是将多态递归的深度限制为
k
depth。多态递归的最有用的情况可以用非常低的深度界限(如k=1或k=2)来推断.无论如何,Haskell类型推理已经是不可判定的,所以这不是不允许的唯一原因。另一个原因可能是性能,它肯定会使类型推理O(k·f(n))而不是O(f(n))因为你可能需要重新做k次。@Bakuriu,我很确定没有多态递归的Haskell 2010有完整的类型推断——在这一点上基本上是Hindley Milner,加上类型类和默认值。你有没有其他的参考说法?至于一些有限的递归深度:这听起来像是一个潜在的有用方法扩展,但它与Haskell报告的风格有很大不同。我会发现这样一个功能对于发现多态递归代码的正确类型签名非常有用。是的,但我认为Haskell 2010之上的所有类型系统扩展都使类型推断不可判定。请注意,例如,类型族“人为地”限制避免不可判定的实例,默认情况下禁止某些格式良好的程序,因此允许“k-递归”“多态递归与这种情况没有太大区别,IMHO。没有多态递归推论的原因正是因为它是不可判定的。这是ghc在获得许多其他不可判定特性之前很久作出的决定。在这一点上,你可以相信我,我当时是Haskell委员会的成员。”@就我所知,给定任何类型良好的多态递归程序,都存在一个有限深度的
k
,这样类型推理就可以工作了。问题是没有有限的
k
适用于每个程序。然而,当时,我没有考虑其他哈斯克尔。
v = fromIntegral v
v :: forall a. Num a => a
v = fromIntegral (v :: Integer)
v :: forall a. Integral a => a
v = fromIntegral (v :: a)