为什么我收到类型错误?

时间:2012-09-11 23:59:19

标签: haskell compiler-errors typeerror function-declaration

在Haskell中,我在定义函数时遇到一些问题,因为我的参数类型与所需的类型不匹配。

例如,我想编写一个带n :: Int的函数,并生成从1到floor的平方根n的整数列表。因此,我希望有一个功能,如:

list :: Int -> [Int]

最初我将函数定义如下:

list :: Int -> [Int]

list n = [1 .. floor (sqrt n)]

当我加载sript时,会出现类型不匹配的错误消息。但是,我不确定我是否与sqrt函数或floor函数的类型不匹配。错误消息如下:

No instance for (Floating Int)
  arising from a use of 'sqrt' at pe142.hs:6:22-27
Possible fix: add an instance declaration for (Floating Int)
In the first argument of 'floor', namely '(sqrt n)'
In the expression: floor (sqrt n)
In the expression: [1 .. floor (sqrt n)]
Failed, modules loaded: none.

有人可以向我解释导致错误的原因以及如何修复错误吗?

4 个答案:

答案 0 :(得分:6)

sqrt需要Floating类的参数,例如一个Double。您传递的是Int,它不是Floating类的实例 - 这就是错误消息告诉您的内容。

因此,要修正错误,请在致电Int之前将Double转换为sqrt。您可以使用fromIntegral功能。

答案 1 :(得分:4)

当我尝试这个时:

list :: Int -> [Int]
list n = [1 .. floor (sqrt n)]

我收到此错误:

../src/scratch.hs:15:16:
    No instance for (RealFrac Int)
      arising from a use of `floor'
    Possible fix: add an instance declaration for (RealFrac Int)
    In the expression: floor (sqrt n)
    In the expression: [1 .. floor (sqrt n)]
    In an equation for `list': list n = [1 .. floor (sqrt n)]

../src/scratch.hs:15:23:
    No instance for (Floating Int)
      arising from a use of `sqrt'
    Possible fix: add an instance declaration for (Floating Int)
    In the first argument of `floor', namely `(sqrt n)'
    In the expression: floor (sqrt n)
    In the expression: [1 .. floor (sqrt n)]

这些错误的含义如下:

  • floor函数无法接受Int类型的参数。它的论点必须是“真正的分数”类型。 (要求提供类型仅支持整数的数字,这是没有意义的。)
  • sqrt函数也不能接受Int类型的参数。它的参数必须是浮点类型。 (平方根通常是不合理的,所以我们需要浮点类型。)

你会发现Haskell对于哪些数字函数可以应用于哪些数字类型非常非常挑剔,非常挑剔这些函数返回的类型,并且它基本上不执行任何隐式转换。我通常会尝试让编译器推断数字代码中的类型,因为类层次结构非常复杂。如果我们省略了函数的类型声明,编译器会推断出这种类型:

list :: (Floating a, Integral t, RealFrac a) => a -> [t]

即,您的list函数函数将浮点“实数分数”作为其参数,并生成一个整数列表作为其结果。因此,例如,list可以使用Double类型的参数并生成[Integer]

但即使省略了类型声明并不意味着你不会遇到麻烦,而且你经常需要使用显式转换;最典型的是你必须使用函数fromIntegral将整数类型转换为小数类型。

答案 2 :(得分:1)

sqrt具有以下类型签名:

Floating a => a -> a

这意味着sqrt接受类型为a的参数并返回类型为a的参数。 restiction是a必须是float类型中的一个类型,通常是Single或Double。 Int不在类型Floating中,因此您需要将n转换为类型为Floating的类型,您可以通过添加对fromIntegral的调用来执行此操作:

list n = [1 .. floor (sqrt (fromIntegral n))]

答案 3 :(得分:0)

每周一次询问这个问题。 (这不是对你的抱怨,只是一个观察。显然这让很多人感到困惑。)

简而言之,sqrt不适用于整数,仅适用于浮点数。 (例如,它不适用于Int,但它适用于Double。)在某些编程语言中,在这种情况下,整数总是自动“提升”为浮点数;但是在Haskell中你必须手动完成。

解决方案,正如其他六个人毫无疑问已经写过的那样,是在那里坚持使用fromIntegral来从整数转换为浮点数。你已经拥有floor,这可以让你在之后转换回整数,正如你所期望的那样。