32

これは、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コンパイラを強制したいと思った人はいませんか?
  • 非網羅的なパターン検索では、すべてではありませんが一部のケースを見つけることができますか?
  • 部分的に定義された関数は正当であると見なされ、上記のような構成を課さないように頻繁に使用されますか?この場合、非網羅的なパターンが役立つ/正当な理由を説明していただけますか?
4

2 に答える 2

38

パターンマッチが網羅的でなくてもかまわない場合があります。たとえば、これは最適な実装ではないかもしれませんが、コンパイルしなかった場合は役に立たないと思います。

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、現在の形式でもコンパイルする必要があると思います。

于 2010-09-27T14:26:20.413 に答える
14

-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

これで、 が(要素の型が にあるときはいつでも )removeDuplicates (duplicate as)が等しいことを簡単に確認できますが、通常、要素の数が奇数であるか、連続する 2 つの要素が異なるため、クラッシュします。クラッシュしない場合は、そもそもによって作成された (または作成された可能性がある)ためです。asEqduplicate (removeDuplicates bs)bsduplicate

したがって、次の法則があります (有効な Haskell ではありません)。

removeDuplicates . duplicate == id
duplicate . removeDuplicates == id (for values in the range of duplicate)

ここで、網羅的でないパターンを防ぎたい場合は、removeDuplicatesreturnMaybe [a]を作成するか、欠落しているケースのエラー メッセージを追加できます。あなたはの線に沿って何かをすることさえできます

newtype DuplicatedList a = DuplicatedList [a]

duplicate :: [a] -> DuplicatedList a
removeDuplicates :: Eq a => DuplicatedList a -> [a]
-- implementations omitted

Haskell 型システムでは「要素の連続したペアが等しい、長さが偶数のリストであること」を簡単に表現できないため、これがすべて必要です (あなたが Oleg でない限り:)

ただし、エクスポートしない場合は、removeDuplicatesここで網羅的でないパターンを使用してもまったく問題ないと思います。エクスポートするとすぐに、入力を制御できなくなり、欠落しているケースに対処する必要があります。

于 2010-09-27T14:39:24.963 に答える