Haskell では、なぜ非網羅的なパターンがコンパイル時エラーにならないのでしょうか?
質問
の続報です Haskell の部分文字列関数を呼び出すと、「関数内の非網羅的なパターン...」というメッセージが表示されるのはなぜですか?
を使用していることを理解しています -Wall
, GHC は非網羅的なパターンに対して警告することができます。部分関数を明示的に定義することが常に可能であることを考えると、デフォルトでコンパイル時エラーにしない理由は何だろうかと疑問に思っています。
f :: [a] -> [b] -> Int
f [] _ = error "undefined for empty array"
f _ [] = error "undefined for empty array"
f (_:xs) (_:ys) = length xs + length ys
この質問はGHC固有のものではありません。
それは...
- Haskell コンパイラにこの種の分析を実行させることを誰も望まなかったのでしょうか?
- 非網羅的なパターン検索では、一部のケースは見つかりますが、すべてのケースが見つかるわけではありません。
- 部分的に定義された関数は正当であるとみなされ、上記のような構成を強制しないほど頻繁に使用されますか?もしそうなら、なぜ非網羅的なパターンが役立つ/正当であるのか説明してもらえますか?
解決
あなたは、パターンマッチが非網羅的であることを気にしない場合があります。これが最適なインプリメンテーションではないかもしれませんしながら、例えば、私はそれをコンパイルしなかった場合、それが役立つだろうとは思わない:
fac 0 = 1
fac n | n > 0 = n * fac (n-1)
これは非網羅されていることを階乗関数の一般的な使用のために本当に問題ではない(負の数はどのような場合に一致しない)。
パターンマッチが網羅された場合も、それは一般的に、コンパイラのために決定することが可能ではないかもしれません。
mod2 :: Integer -> Integer
mod2 n | even n = 0
mod2 n | odd n = 1
ここですべてのケースをカバーしなければならないが、コンパイラは、おそらくそれを検出することはできません。警備員は、任意の複雑な可能性がありますのでパターンが網羅されている場合、コンパイラは常に決定することはできません。もちろん、この例では、より良いotherwise
で書かれるだろうが、私はそれはまた、現在の形でコンパイルべきだと思います。
他のヒント
あなたはエラーに警告を有効にする-Werror
を使用することができます。あなたがエラーにだけ非網羅的パターンの警告を回すことができる場合、私は知りません、申し訳ありません!
あなたの質問の3番目の部分についてます:
私は時々、緊密に協力し、あなたが簡単にHaskellで表現できない性質を持っている傾向がある関数の数を記述します。少なくとも、これらの機能のいくつかは、通常は「消費者の、非網羅的なパターンを持っている傾向があります。これは、「ソートの」は、それぞれ他の逆で機能、例えば、アップしています。
おもちゃの例:
duplicate :: [a] -> [a]
duplicate [] = []
duplicate (x:xs) = x : x : (duplicate xs)
removeDuplicates :: Eq a => [a] -> [a]
removeDuplicates [] = []
removeDuplicates (x:y:xs) | x == y = x : removeDuplicates xs
次に、それは、要素または2つの連続した要素が異なるの奇数があるためremoveDuplicates (duplicate as)
は、(要素タイプはas
であるときはいつでも)Eq
に等しいが、一般duplicate (removeDuplicates bs)
にクラッシュすることを確認するために非常に簡単です。それがクラッシュしない場合はbs
を作製した(またはによって生成されている可能性が)最初の場所でduplicate
ので、それはです!
私たちは、以下の法則(無効ハスケル)を持っているのでます:
removeDuplicates . duplicate == id
duplicate . removeDuplicates == id (for values in the range of duplicate)
あなたはここで非網羅的なパターンを阻止したい場合は、さて、あなたはremoveDuplicates
リターンMaybe [a]
を作る、または不足している場合のエラーメッセージを追加することができます。あなたも、
newtype DuplicatedList a = DuplicatedList [a]
duplicate :: [a] -> DuplicatedList a
removeDuplicates :: Eq a => DuplicatedList a -> [a]
-- implementations omitted
:あなたは簡単にHaskellの型システムでは(あなただオレグない限り)「要素の連続したペアが等しいと、偶数長のリストであること」表現することはできませんので、はこのすべてが必要であり、
あなたがremoveDuplicates
をエクスポートしていない場合は、
しかし、私はそれがここで非網羅的なパターンを使用することは完全に大丈夫だと思います。すぐにあなたがそれをエクスポートしそうであるようにと、あなたが入力のコントロールを失うことになるし、不足している場合に対処する必要があります!