为什么 multiplesOf num max = [num*k | k <- [1..floor (max/num)]] 抛出错误?



我试图在上限max下创建一组数字num的所有倍数。我在Haskell中编写了以下函数:

multiplesOf num max = [num*k | k <- [1..floor (max/num)]]

为什么这个函数在运行时会抛出以下错误,如何修复?

<interactive>:26:1: error:
• Ambiguous type variable ‘a0’ arising from a use of ‘print’
prevents the constraint ‘(Show a0)’ from being solved.
Probable fix: use a type annotation to specify what ‘a0’ should be.
These potential instances exist:
instance Show Ordering -- Defined in ‘GHC.Show’
instance Show Integer -- Defined in ‘GHC.Show’
instance Show a => Show (Maybe a) -- Defined in ‘GHC.Show’
...plus 22 others
...plus 18 instances involving out-of-scope types
(use -fprint-potential-instances to see them all)
• In a stmt of an interactive GHCi command: print it

例如,在输入multiplesOf 3 1000时引发此错误。

定义函数时没有错误。当您想使用函数时,错误会更多。

如果我们看看你构建的函数的类型,我们会看到:

multiplesOf :: (RealFrac t, Integral t) => t -> t -> [t]

所以这里的输入值和输出值的类型都应该是IntegralRealFrac。这意味着这个数字应该是Integral,但同时支持真正的除法。没有多少类型可以满足这些要求。

这个问题源于您在这里使用(/)floor,这暗示maxnumRealFrac,但floor的结果是Integral,然后您再次使用num将超出此范围的数字相乘。

但是,您可以通过使用div :: Integral a => a -> a -> a来减少类型约束的数量。因此,这是整数除法,结果被截断为负无穷大,因此我们可以实现如下函数:

multiplesOf :: Integral i => i -> i -> [i]
multiplesOf num max = [num*k | k <- [1..div max num]]

或者我们甚至可以省去除法、乘法等运算的麻烦,并使用一个为我们做这项工作的范围表达式:

multiplesOf :: (Num n, Enum n) => n -> n -> [n]
multiplesOf num max = [num, (num+num) .. max]

后者是更少的约束,因为Integral i意味着Real iEnum i