2012-09-05 14 views
8

私は、次のHaskellコードしているタイプ`のInt予想と一致しませんでした:「整数実際の型と `」が

-- 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 [email protected](_, _, x) [email protected](_, _, 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になるのですか?または、このエラーの原因となる他のものがありますか? phiの種類は、それがIntegerあるべきと言いながら

答えて

15

を使用し、Integerに明示的なIntを変更する必要がある場合。これは、どの関数に渡すかを知っているためです。関数phi :: Integer -> Integerがあり、phi 0を呼び出すと、Haskellはその特定の0Integerである必要があることを知っています。私が関数pho :: Int -> Intpho 0と呼んでも問題ありません。 特に0Intと推定されます。

しかしIntInteger異なる種類あり、一つの特定の0phiphoの両方に渡すことができる方法はありません。

maxRatioが扱うタプルは(あなたによって)(Int, Int, Double)と入力されていますが、このタプルの1つは(n, phi n, ratio)として構成されています。 phiIntegerを受け取り、返すので、その式のnIntegerでなければなりません。しかしそれはmaxRatioのために働かないので、あなたはエラーを得る。これによって

は、あなたが実際に(IntまたはInteger)欲しかったタイプ、あなたがする必要があるすべては、彼らが数の同じ種類で作業しているように、phiまたはmaxRatioの型シグネチャを変更です。ハスケルはあなたの文字通り書かれた0がその仕事をするために必要な数字のタイプであることを決定します。となります。エラーは、具体的をメッセージとして送ら

注意は、それがIntと予想されたこと(n, phi n, ratio)nだったし、実際にIntegerだったことを言いました。 (0, 0, 0.0)タプルは決して言及されません。しばしば型エラーはコンパイラがあなたを指している場所以外のどこかで発生することがあります(すべてのコンパイラが行うことができるのは、推論のさまざまな連鎖が何かの型に一貫性のない要件をもたらし、プロセス全体のどの部分が "間違っている" )しかし、この場合、それはかなりうまくいった。

Haskellは不可解なエラーメッセージの(かなり正当化)悪評を取得しますが、それは多くの問題が何であるかをコンパイラがあなたを語っているからスタートするのに役立ち、それが不満だ事実が生じた理由を把握しようとすることができますあなたのコードから。これは最初は辛いでしょうが、この種のエラーを本当にすばやく見つけるのに役立つHaskellのエラーメッセージ(少なくともより単純なもの)で基本的なリテラシーを素早く開発し、コンパイラを非常に強力なエラー検出にしますあなたのためのシステム。

+0

明確な説明をいただきありがとうございます。私はそのタイプで '' 0''が多型であると思っていましたが、私のnoobの目はエラーを与えた型推論の他の理由を見ることができませんでした。もちろん、私は 'maxRatio'の明示的な型宣言を見逃しました。 –

4

nは、原因maxRatioの種類にIntと推測されています。最も簡単な解決策は、を使用するようにmaxRatioのタイプを変更することです。それはそれらの値には触れないため、ちょうどaです。

+0

Doh!私はその詳細を逃した。おそらくIntegerをほとんど独占的に使用することを学ぶ前に、私が少し前に書いたコードを見直しています。 –

3

それは推測されているので、タイプシグネチャを変更することができますmaxRatio。それでも、あなたはHaskellは、一般的に、あなたがするそれらを必要とする適切などんなタイプのような0として数値リテラルの型を推測できるtoInteger :: (Integral a) => a -> Integer

+0

私は通常、 'fromIntegeral'を使用します。特に' length'を使用しているときはそうです。 'toInteger'ではなく' fromIntegral'を使うことに違いがありますか? –

+0

@ Code-Guru: 'fromIntegral'は' Num'型を返すことしかできないと思うので、どの型を推測するのかは少し分かりません。 – amindfv

+1

@ Code-Guru:実際には、fromIntegralはfromIntegral = fromIntegerとして定義されています。 toInteger' - 柔軟性と可読性の間のトレードオフになります。 – amindfv

1

タイプシグネチャに一貫性がありません - Intを全体でIntegerに置き換えてください。