无法将预期类型"Int"与实际类型"Integer"匹配

Cod*_*ice 8 haskell

我有以下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 -> Intpho 0; 特定0被推断为一个Int.

然而Int,Integer它们是不同的类型,并且没有办法将一个特定的0传递给两者phipho.

你的问题只是maxRatio处理的元组是由你键入的(Int, Int, Double),但是那个元组被构造为(n, phi n, ratio).由于phi获取和返回Integer,该n表达式必须是一个Integer.但那不起作用maxRatio,所以你得到了错误.

根据您实际想要的类型(IntInteger),您需要做的就是更改类型签名,phi或者maxRatio使用相同类型的数字.Haskell将决定你的字面编写0s是为了使其工作所必需的任何数字类型,只要有一个可以使它工作!

请注意,错误消息特别告诉您,它n(n, phi n, ratio)那里预计是一个Int,实际上是一个Integer.该(0, 0, 0.0)元组从未被提及.通常,类型错误源于编译器指向您的位置以外的其他位置(因为编译器可以做的就是发现不同的推理链对某些类型的类型产生不一致的要求,无法知道整个过程的哪个部分是"错误的" ),但在这种情况下,它做得很好.

Haskell得到了一个(相当合理的)糟糕的代表,因为它不可思议的错误消息,但它可以帮助很多东西从编译器告诉你的问题开始,并试图弄清楚为什么它的抱怨来自你的代码.这一开始会很痛苦,但是你会很快在Haskell的错误信息(至少是更直接的错误信息)中发展出基本知识,这将有助于你真正快速地发现这些错误,这使编译器成为一个非常强大的错误检测系统为你服务.


ham*_*mar 5

n被推断为Int由于 的类型maxRatio,而类型phi表示应该是Integer。最简单的解决方法是更改maxRatio要使用的类型,Integer甚至只是a因为它不涉及这些值。