为什么我不能声明推断的类型? [英] Why can't I declare the inferred type?

查看:123
本文介绍了为什么我不能声明推断的类型?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述



I have the following:

runcount :: (Eq a, Num b) => [a] -> b
runcount = runcountacc 0

runcountacc :: (Eq a, Num b) => b -> [a] -> b
runcountacc n (_:[]) = runcountacc (n+1) []
runcountacc n (x:xs) = runcountacc (n+(if head xs==x then 0 else 1)) xs 
runcountacc n _ = n

当我尝试将它加载到拥抱:

Which generates this error when I try to load it into Hugs:

:6 - Cannot justify constraints in explicitly typed binding
*** Expression    : runcountacc
*** Type          : (Eq a, Num b) => b -> [a] -> b
*** Given context : (Eq a, Num b)
*** Constraints   : Eq c

加载到ghci时出现以下错误:

And the following error when loaded into ghci:

:6:23: Ambiguous type variable `a0' in the constraint:
  (Eq a0) arising from a use of `runcountacc'
Probable fix: add a type signature that fixes these type variable(s)
In the expression: runcountacc (n + 1) []
In an equation for `runcountacc':
   runcountacc n ([x]) = runcountacc (n + 1) []

然而,当 runco​​untacc 的类型声明被删除时:

However when the type declaration of runcountacc is removed:

runcount :: (Eq a, Num b) => [a] -> b
runcount = runcountacc 0

runcountacc n (_:[]) = runcountacc (n+1) []
runcountacc n (x:xs) = runcountacc (n+(if head xs==x then 0 else 1)) xs 
runcountacc n _ = n

代码加载正常,当询问ghci是什么类型的 runco​​untacc 时,我们得到以下结果:

The code loads fine and when ghci is asked what the type of runcountacc is, we get the following:

λ> :t runcountacc 
runcountacc :: (Num a, Eq a1) => a -> [a1] -> a

为什么我不能声明 runco​​untacc

Why can't I declare the inferred type of runcountacc?

推荐答案

我的猜测是,当你遗漏了类型签名时,Haskell假定你并不打算使用多态递归(对于哪种类型推断不是很有效)。相应地,当您对 runco​​untacc(n + 1)[] 进行递归调用时,列表元素类型将被视为与原始函数调用中的相同。通常的Hindley-Milner过程可以正常工作,为 runco​​untacc 计算一个统一的单形态类型,然后通过泛化自由类型变量和未解约束来形成一个类型方案。

My guess is that when you leave out the type signature, Haskell assumes you're not intending to use polymorphic recursion (for which type inference is not so effective). Correspondingly, when you make that recursive call to runcountacc (n + 1) [], the list element type is taken to be the same as in the original function call. The usual Hindley-Milner process works fine, computing a uniform monomorphic type for runcountacc, then forming a type scheme by generalizing over the free type variables and unsolved constraints.

然而,只要你写了一个类型签名,就允许多态递归的可能性,当你调用 runco​​untacc(n + 1)[] ,没有理由认为 [] 的未确定元素类型应该是特别的。然而,这个未确定类型仍然需要一个 Eq 实例来满足 runco​​untacc 上的约束,并且没有办法计算出其中 Eq 要使用的实例。它是真正含糊不清的。

However, as soon as you write a type signature, you allow for the possibility of polymorphic recursion, and when you call runcountacc (n + 1) [], there is no reason to assume that the undetermined element type for [] should be anything in particular. However, this undetermined type still needs an Eq instance to satisfy the constraints on runcountacc, and there's no way to figure out which Eq instance to use. It's genuinely ambiguous.

有很多方法可以重写这段代码来解决这个模糊问题。

There are plenty of ways you can rewrite this code to sort out this ambiguity.

这篇关于为什么我不能声明推断的类型?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆