我有以下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
Run Code Online (Sandbox Code Playgroud)
这给出了以下错误:
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))]'
Run Code Online (Sandbox Code Playgroud)
我怀疑在三联(0, 0, 0.0)
中0是类型Int
.是0
始终键入Int
或ghci的推导类型Int
在这种情况下?如果是后者,我怎么强迫它Integer
改为?或者是否有其他原因会导致此错误?
Ben*_*Ben 16
Haskell通常可以推断出数字文字的类型,例如0
你需要它们的任何类型.这是因为它知道你传递给他们的功能; 如果我有一个函数phi :: Integer -> Integer
,我打电话phi 0
,Haskell知道那个特定的0
必须是一个Integer
.它也很好,如果我调用一个函数pho :: Int -> Int
用pho 0
; 该特定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
s是为了使其工作所必需的任何数字类型,只要有一个可以使它工作!
请注意,错误消息特别告诉您,它n
在(n, phi n, ratio)
那里预计是一个Int
,实际上是一个Integer
.该(0, 0, 0.0)
元组从未被提及.通常,类型错误源于编译器指向您的位置以外的其他位置(因为编译器可以做的就是发现不同的推理链对某些类型的类型产生不一致的要求,无法知道整个过程的哪个部分是"错误的" ),但在这种情况下,它做得很好.
Haskell得到了一个(相当合理的)糟糕的代表,因为它不可思议的错误消息,但它可以帮助很多东西从编译器告诉你的问题开始,并试图弄清楚为什么它的抱怨来自你的代码.这一开始会很痛苦,但是你会很快在Haskell的错误信息(至少是更直接的错误信息)中发展出基本知识,这将有助于你真正快速地发现这些错误,这使编译器成为一个非常强大的错误检测系统为你服务.
n
被推断为Int
由于 的类型maxRatio
,而类型phi
表示应该是Integer
。最简单的解决方法是更改maxRatio
要使用的类型,Integer
甚至只是a
因为它不涉及这些值。