2016-03-21 7 views
1

を式チェックしなければならない場合は、次のreverse'機能はEq t => [t] -> [t]を入力しました:はなぜリストの要素の型は、空のリストについては、

reverse' list | list == [] = [] 
       | otherwise = (reverse' listTail) ++ [listHead] 
       where (listHead : listTail) = list 

なぜリストの要素は、型クラスEqのメンバーでなければなりませんか?私はtのリストはequatableでなければならない、私の直感では

。平等のための要素が、それらが中に含まれているリストを比較していないんだけど、t自体にはありません。

+1

タイプの問題とは別に、あなたの関数がO(n^2)である理由が分かりますか?あなたはそれをO(n)にする方法を理解できますか? – dfeuer

+0

この質問は、http://stackoverflow.com/questions/24664501/no-instance-for-eq-a0-arising-from-a-use-ofの近くにありますが、これはもっと重要ですポイントと良い答えがあります。 – dfeuer

+1

ちなみに、コーディングスタイルは危険な部分演算を使っています: 'list'が空であれば、変数' listHead'と 'listTail'は間違った値(AKAボトム)に束縛されます。その場合、これらの変数を使用しようとすると、プログラム全体がクラッシュします。プログラマは、非ヌルテストでこのような使用法を注意深く守る必要があります。これと比較すると、以下の答えで示唆されているように、適切で包括的なパターンマッチングを使用すると、偏差問題が修正されます。また、 'Eq'制約を必要としません。これは、間違いなくガードを使用するよりパターンマッチングを常に優先させるべき理由です。 – chi

答えて

8

です。つまり、一般的なケースでは、a == dを説明できない限り、[a, b, c] == [d, e, f]を説明する実際の方法はありません。

これはあなたの場合、より一般的な1の両方のためのすべての作品の後にリストに(==)の種類に反映されます。

(==) :: (Eq a) => [a] -> [a] -> Bool 

あなたが別のリストと平等のリストを比較する必要はありませんが実際には、リストが空であるかどうかをチェックしたいだけです。

null :: [a] -> Bool 

は、はるかに良い選択です。また、リストの構造上でパターンマッチングを使用するだけなので、等式制約はありません。型クラス制約を必要としないものです。

null :: [a] -> Bool 
    null [] = True 
    null (_ : _) = False 

さらにあなたの場合は、あなた自身がパターンマッチングを行うだけでしょうか、結局のところ、あなたはすでに正しいパターンです!

これはそれがコンパイラによって自明行うことができますクラッシュしないことを検証するため、慣用的なHaskellのに非常に近いです
reverse' [] = [] 
reverse' (listHead : listTail) = (reverse' listTail) ++ [listHead] 

は、我々は徹底的にそれをチェックすることができるような方法ですべてのケースを取り上げました。あなたのバージョンでは、コードがうまく動作することを確認するために、コードを通して2つのパスをトレースし、そのパターンマッチを行ったブランチで空のリストが決して終わらないようにする必要がありました。これはちょっとした問題ではありますが、非常に迅速に難易度が上がります。

5

(==) :: Eq a => a -> a -> BoolのみEqのインスタンスに対して機能し、その要素はEqのインスタンスである場合[]Eqの唯一のインスタンスであるので:代わり

instance (Eq a) => Eq [a] where 
    ... 

、リストがあるかどうかをチェックするnull :: [a] -> Boolまたはパターンマッチングを使用空:我々は平等のために彼らの要素を比較することができた場合、我々は唯一の平等のための一般的にリストを比較することができますので、

reverse' [] = [] 
reverse' xs = ... 
+2

またはパターンマッチング。 – sepp2k

関連する問題