2009-04-27 16 views
59

私はハスケルを初め、「無限型を構築できません」というエラーに直面しています。なぜこのHaskellコードは "無限型"エラーを生成しますか?

実際には、このエラーが何を意味するのかについての良い説明を見つけることができませんでした。私の基本的な質問を超えて「無限のタイプ」のエラーを説明できれば、それ。

は、ここでは、コードです:

intersperse :: a -> [[a]] -> [a] 

-- intersperse '*' ["foo","bar","baz","quux"] 
-- should produce the following: 
-- "foo*bar*baz*quux" 

-- intersperse -99 [ [1,2,3],[4,5,6],[7,8,9]] 
-- should produce the following: 
-- [1,2,3,-99,4,5,6,-99,7,8,9] 

intersperse _ [] = [] 
intersperse _ [x] = x 
intersperse s (x:y:xs) = x:s:y:intersperse s xs 

そして、ここでインタプリタにロードしようとしているエラーです:

Prelude> :load ./chapter.3.ending.real.world.haskell.exercises.hs 
[1 of 1] Compiling Main (chapter.3.ending.real.world.haskell.exercises.hs, interpreted) 

chapter.3.ending.real.world.haskell.exercises.hs:147:0: 
Occurs check: cannot construct the infinite type: a = [a] 
When generalising the type(s) for `intersperse' 
Failed, modules loaded: none. 

感謝。

- ここ

一部は、コードやHaskellでは "無限の種類" のエラーに対処するための一般的なガイドライン修正される:

修正されたコード

intersperse _ [] = [] 
intersperse _ [x] = x 
intersperse s (x:xs) = x ++ s:intersperse s xs 

何問題は:

私の署名の状態2番目のパラメータは、リストのリストです。したがって、「s(x:y:xs)」とパターンが一致すると、xとyはとなり、リストはとなりました。それでも、xとyはリストではなく要素として扱っていました。

「無限のタイプ」のエラーに対処するためのガイドライン:

あなたはこのエラーを取得するときに、あなたが扱っている様々な変数の型を忘れてしまった時、ほとんどの、そしてあなたあたかもそれが何か他のタイプであるかのように変数を使用しようとしました。すべてのタイプと使用方法を注意深く見てください。これは通常、問題を明らかにするでしょう。

+1

別の良いヒント:型を明示的に宣言します。これにより、コンパイラは何かをチェックします。 –

+1

これで問題は解決しますが、なぜコンパイラは「無限型を構築できませんか」と言います。どういう意味ですか?これらの操作をサポートしない型に対して操作を実行しようとしている場合、なぜコンパイラーはそのようなことを言っていませんか? – freedrull

+9

+1(質問訂正された問題はガイドライン) – Dacav

答えて

27

問題は最後の節にあります。ここでは、xとyを要素として扱いますが、それらはリストです。これは動作します:

intersperse _ [] = [] 
intersperse _ [x] = x 
intersperse s (x:y:xs) = x ++ [s] ++ y ++ intersperse s xs 

ので、無限の種類のエラーが発生します。オペレータが入力した - > A - - > [A]は[A]として扱いながら、[A]> - > [A]をこれは[a]がaで識別されなければならないことを意味し、これはaが無限に入れ子にされたリストであることを意味する。それは許可されていません(とにかく、あなたが意味するものではありません)。

編集:上記のコードには別のバグもあります。それはする必要があります:

intersperse _ [] = [] 
intersperse _ [x] = x 
intersperse s (x:xs) = x ++ [s] ++ intersperse s xs 
+0

ありがとうございます。私はそれらを外に出してここに戻ってきて、あなたの応答を見ました。これは私にとって優れた検証でした。あなたは私のバグよりも私のバグを改善しました。私のバグは、それがyとxsの間の区切り文字をスキップしていたことでした。これを修正するために、次のような別のレベルのパターンマッチングを導入しました: intersperse s(x:y:[])= x ++ s:y intersperse s(x:y:xs)= intersperse s [x、 y] ++ s:intersperse s xs しかし、その余分なレベルを必要とせずにバグを修正したようです。 –

+1

ここで私が学ぶ教訓は次のとおりです。「無限のタイプのエラーに直面するとき、あなたはおそらくあなたが扱っているタイプを忘れているので、あなたがすることを意図しないタイプのことをやっているでしょう。変数は、それは通常、問題を明らかにするでしょう。あなたが追加したり変更したりするものはありますか? –

+0

それは確かに正しいです、私はそれを何も変えません。無限型は許されないので、無限型エラーとは、ある関数が不正な型の引数を受け取ることを意味します。 RWHで幸運: – Stephan202

2

私は間違っているかもしれませんが、より困難な問題を解決しようとしているようです。あなたのバージョンintersperseは、値を配列に散在させるだけでなく、1つのレベルを平坦にします。

HaskellのListモジュールは実際に散在関数を提供します。これは、の間に指定された値を、リスト内のすべての要素に置きます。たとえば:

intersperse 11 [1, 3, 5, 7, 9] = [1, 11, 3, 11, 5, 11, 7, 11, 9] 
intersperse "*" ["foo","bar","baz","quux"] = ["foo", "*", "bar", "*", "baz", "*", "quux"] 

私は、これはあなたが、それは私の教授は、私はHaskellのを学んでいたとき、私たちがやりたいことだから何をしたいかであると仮定しています。もちろん、私は完全に外に出ることができました。

+0

コメントありがとうございます。しかし、この場合、私は「Real World Haskell」の第3章の最後から7練習をしているので、1つのレベルを平坦にしたいと思います。 –

+0

Gotcha。もし私が本を持っていたら、私が書いた前に私はチェックしただろう。悲しいかな、私ができることは、推測だった。とにかくソートされてうれしいです。 :-) –

+4

本の内容は、オンラインで自由に入手できます。http://book.realworldhaskell.org/ – Stephan202

0

また、エラーの意味を説明するthisが見つかりました。

インタプリタ/コンパイラが私にこのエラーを通知するたびに、型パラメータ化されたタプルを型パラメータとして使用しているためです。すべてによって正しく動作し、型変数を含む関数の型定義を削除します。

私はそれを修正して関数型定義を保持する方法をまだ理解できません。

3

明示的な型定義を追加すると、コンパイラの型エラーメッセージがより意味をなさないことがあります。しかし、この場合、明示的な型指定はコンパイラのエラーメッセージを悪化させます。

Occurs check: cannot construct the infinite type: a = [a] 
    Expected type: [a] -> [[a]] -> [[a]] 
    Inferred type: [a] -> [[a]] -> [a] 
In the second argument of `(:)', namely `intersperse s xs' 
In the second argument of `(:)', namely `y : intersperse s xs' 

明確にコードのバグに向かってポイント:

は、私はGHCが分散配置のタイプを推測させたときに何が起こるか見て。このテクニックを使うと、他の人たちが示唆しているように、あらゆることを凝視したり、タイプについて懸命に考える必要はありません。

関連する問題