0

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

例如,我想编写一个函数,它接受一个n :: Int并产生从 1 到 的floor平方根的整数列表n。因此,我将有一个功能,例如:

list :: Int -> [Int]

最初我将函数定义如下:

list :: Int -> [Int]

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

当我加载脚本时,出现类型不匹配的错误消息。但是,我不确定我是否不匹配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

4 回答 4

6

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

因此,要修复错误,请在调用之前将您的转换Int为 a 。您可以使用该功能。DoublesqrtfromIntegral

于 2012-09-12T00:09:54.107 回答
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函数不能接受 type 的参数Int。它的参数必须是“实分数”类型。(要求类型只支持整数的数字的下限是没有意义的。)
  • sqrt函数也不能接受类型的参数Int。它的参数必须是浮点类型。(平方根通常是无理数,所以我们需要浮点类型。)

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

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

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

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

于 2012-09-12T00:12:23.447 回答
1

sqrt 具有以下类型签名:

Floating a => a -> a

这意味着 sqrt 接受一个类型为 a 的参数并返回一个类型为 a 的参数。限制是 a 必须是类型类 Floating 中的类型,通常是 Single 或 Double。Int 不在类型类 Floating 中,因此您需要将 n 转换为类型类 Floating 中的内容,您可以通过添加调用来做到这一点fromIntegral

list n = [1 .. floor (sqrt (fromIntegral n))]
于 2012-09-12T00:12:30.320 回答
0

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

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

The solution, as half a dozen other people have no doubt already written, is to stick a fromIntegral in there to convert from integers to floating-point. You already have floor in there, which lets you convert back to an integer afterwards, as you'd expect.

于 2012-09-12T11:01:53.023 回答