我试图在上限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]
所以这里的输入值和输出值的类型都应该是Integral
和RealFrac
。这意味着这个数字应该是Integral
,但同时支持真正的除法。没有多少类型可以满足这些要求。
这个问题源于您在这里使用(/)
和floor
,这暗示max
和num
是RealFrac
,但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 i
和Enum i
。