![](/img/trans.png)
[英]Haskell Couldn't match expected type `Integer' with actual type `[Integer]'
[英]Couldn't match expected type `Int' with actual type `Integer'
我有以下Haskell代码:
-- Problem 69
import ProjectEuler
phi :: Integer -> Integer
phi n = n * product [p - 1 | p <- primeDivisors n] `div` product [p | p <- primeDivisors n]
-- primeDivisors n is a list of the prime divisors of n
maxRatio :: (Int, Int, Double) -> (Int, Int, Double) -> (Int, Int, Double)
maxRatio t1@(_, _, x) t2@(_, _, y)
| x > y = t1
| otherwise = t2
main = print (foldl
maxRatio
(0, 0, 0.0)
[(n, phi n, ratio) | n <- [2..max], let ratio = fromIntegral n / (fromIntegral (phi n))]
)
where max = 1000
这给出了以下错误:
Couldn't match expected type `Int' with actual type `Integer'
In the expression: n
In the expression: (n, phi n, ratio)
In the third argument of `foldl', namely
`[(n, phi n, ratio) |
n <- [2 .. max],
let ratio = fromIntegral n / (fromIntegral (phi n))]'
我怀疑在三元组(0, 0, 0.0)
,0是Int
类型。 在这种情况下, 0
总是输入Int
还是ghci将类型推断为Int
? 如果是后者,我该如何强制它输入Integer
? 或者是否有其他原因会导致此错误?
Haskell通常可以推断出数字文字的类型,例如0
就像你需要它们一样合适的类型。 这是因为它知道你传递给他们的功能; 如果我有一个函数phi :: Integer -> Integer
,我调用phi 0
,Haskell知道那个特定的0
必须是一个Integer
。 如果我用pho 0
调用函数pho :: Int -> Int
也没关系; 该特定0
被推断为一个Int
。
但是Int
和Integer
是不同的类型,并且不能将特定的0
传递给phi
和pho
。
你的问题只是maxRatio
处理的元组是由你输入的( (Int, Int, Double)
,但是这样的元组被构造为(n, phi n, ratio)
。 由于phi
接受并返回Integer
,因此该表达式中的n
必须是Integer
。 但是那对maxRatio
,所以你得到了错误。
根据您实际想要的类型( Int
或Integer
),您需要做的就是更改phi
或maxRatio
的类型签名,以便它们使用相同类型的数字。 Haskell将决定你的字面上写的0
是什么数字类型是必要的,以使其工作, 只要有一个可以使它工作!
需要注意的是传递消息的错误明确告诉你,这是n
在(n, phi n, ratio)
这是预计的Int
和实际上是一个Integer
。 永远不会提到(0, 0, 0.0)
元组。 通常,类型错误源于编译器指向您的位置以外的其他位置(因为编译器可以做的就是发现不同的推理链对某些类型的类型产生不一致的要求,无法知道整个过程的哪个部分是“错误的” ),但在这种情况下,它做得很好。
Haskell得到了一个(相当合理的)糟糕的代表,因为它不可思议的错误消息,但它可以帮助很多东西从编译器告诉你的问题开始,并试图弄清楚为什么它的抱怨来自你的代码。 这一开始会很痛苦,但是你会很快在Haskell的错误消息(至少是更直接的错误消息)中开发一个基本知识,这将有助于你真正快速地发现这些类型的错误,这使编译器成为一个非常强大的错误检测系统为你服务。
由于maxRatio
的类型, n
被推断为Int
,而phi
的类型则表示它应该是Integer
。 最简单的解决方法是将maxRatio
的类型maxRatio
为使用Integer
,甚至只更改a
因为它不会触及这些值。
它是推断的,所以你可以改变maxRatio
的类型签名。 但是,如果您需要将显式Int
更改为Integer
,请使用toInteger :: (Integral a) => a -> Integer
您的类型签名不一致 - 始终将Int
替换为Integer
。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.