web-dev-qa-db-ja.com

このHaskellコードが「無限型」エラーを生成するのはなぜですか?

私は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はlistsになりました。それでも、私はxとyをリストではなく要素として扱っていました。

「無限型」エラーを処理するためのガイドライン:

ほとんどの場合、このエラーが発生すると、扱っているさまざまな変数の型を忘れてしまい、変数を他の型のように使用しようとしました。それが何であるかより。すべてがどのタイプであるか、それをどのように使用しているかを注意深く見ると、通常は問題が明らかになります。

72
Charlie Flowers

問題は最後の節にあり、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は、aが無限にネストされたリストであることを意味します。それは許可されていません(とにかくあなたの言っていることではありません)。

編集:上記のコードには別のバグもあります。そのはず:

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

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

Ghcに散在のタイプを推測させるとどうなるか見てみましょう。

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'

それは明らかにコードのバグを指し示しています。この手法を使用すると、他の人が提案しているように、すべてをじっと見つめ、タイプについて一生懸命考える必要はありません。

4
Joey

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

HaskellのListモジュールは、実際にはintersperse関数を提供します。リストのevery要素の間に与えられた値を入れます。例えば:

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を学んでいたときに教授が望んでいたことだから、これがあなたのやりたいことだと思う。もちろん、完全に外出することもできます。

3
Samir Talwar

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

インタープリター/コンパイラーがこのエラーを出すたびに、正式なパラメーターとして型パラメーター化されたタプルを使用しているためです。型変数を含んでいた関数の型定義をremovingすることにより、すべてが正しく機能します。

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

0
Dacav