In Haskell, warum nicht erschöpfende Muster sind nicht Kompilierung-Fehler?
Frage
Dies ist ein Follow-up von Warum erhalte ich "..." wenn ich meine invoke Haskell String-Funktion?
Ich verstehe, dass -Wall
verwenden, können GHC warnen vor nicht erschöpfende Muster. Ich frage mich, was ist der Grund für das nicht einen Fehler bei der Kompilierung von Standard gegeben zu machen, dass es immer möglich ist, explizit eine Teilfunktion zu definieren:
f :: [a] -> [b] -> Int
f [] _ = error "undefined for empty array"
f _ [] = error "undefined for empty array"
f (_:xs) (_:ys) = length xs + length ys
Die Frage ist nicht GHC spezifisch.
Ist es, weil ...
- niemand wollte einen Haskell Compiler erzwingen, diese Art von Analyse durchführen?
- eine nicht erschöpfende Mustersuche einige aber nicht alle Fälle finden kann?
- teilweise definierte Funktionen werden als legitim und verwenden oft genug nicht die Art von Konstrukt oben gezeigt zu verhängen? Wenn dies der Fall ist, können Sie mir erklären, warum nicht erschöpfende Muster sind hilfreich / legitim?
Lösung
Es gibt Fälle, in denen es Ihnen nichts ausmacht, dass ein Mustererkennung ist nicht erschöpfend. Zum Beispiel, während dies vielleicht nicht die optimalen Umsetzung sein, glaube ich nicht, es würde helfen, wenn es nicht kompiliert haben:
fac 0 = 1
fac n | n > 0 = n * fac (n-1)
Dass dies nicht abschließende (negative Zahlen nicht übereinstimmen jeden Fall) nicht wirklich wichtig für die typische Nutzung der Fakultäts-Funktion.
Auch könnte es im allgemeinen nicht möglich sein, für den Compiler zu entscheiden, ob eine Mustererkennung ist vollständig:
mod2 :: Integer -> Integer
mod2 n | even n = 0
mod2 n | odd n = 1
Hier sollten alle Fälle abgedeckt werden, aber der Compiler wahrscheinlich nicht erkennen kann. Da die Wachen beliebig komplex sein können, kann der Compiler nicht immer entscheiden, ob die Muster erschöpfend sind. Natürlich würde dieses Beispiel besser mit otherwise
geschrieben werden, aber ich denke, dass es auch in seiner jetzigen Form zusammenstellen sollte.
Andere Tipps
Sie können -Werror
verwenden Warnungen in Fehler zu machen. Ich weiß nicht, wenn Sie nur die nicht erschöpfende Muster Warnungen in Fehler machen können, sorry!
Was den dritten Teil Ihrer Frage:
Ich schreibe manchmal eine Reihe von Funktionen, die eng zusammenarbeiten neigen und haben Eigenschaften, die man nicht so leicht in Haskell ausdrücken kann. Wenigstens neigen einige dieser Funktionen nicht erschöpfende Muster haben, in der Regel die ‚Verbraucher‘. Dies kommt zum Beispiel in Funktionen, die ‚Art-of‘ Umkehrungen voneinander sind.
Ein Spielzeug Beispiel:
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
Jetzt ist es ziemlich einfach, zu sehen, dass removeDuplicates (duplicate as)
zu as
gleich ist (immer dann, wenn der Elementtyp in Eq
ist), aber im Allgemeinen duplicate (removeDuplicates bs)
stürzt ab, weil es eine ungerade Anzahl von Elementen oder 2 aufeinander folgende Elemente unterscheiden. Wenn es nicht abstürzt, dann ist es, weil bs
wurde erstellt (oder konnte durch produziert worden) duplicate
in erster Linie !.
So wir die folgenden Gesetze (nicht gültig Haskell):
removeDuplicates . duplicate == id
duplicate . removeDuplicates == id (for values in the range of duplicate)
Wenn Sie jetzt hier nicht erschöpfende Muster verhindern möchten, können Sie removeDuplicates
Rückkehr Maybe [a]
machen, oder Fehlermeldungen für die fehlenden Fälle hinzufügen. Man könnte sogar etwas entlang der Linien von tun
newtype DuplicatedList a = DuplicatedList [a]
duplicate :: [a] -> DuplicatedList a
removeDuplicates :: Eq a => DuplicatedList a -> [a]
-- implementations omitted
All dies ist notwendig, weil man nicht einfach ausdrücken kann ‚eine Liste der noch lang ist, mit aufeinanderfolgenden Paaren von Elementen gleich‘ in dem Haskell Typ-System (es sei denn, du bist Oleg:)
Aber wenn Sie removeDuplicates
nicht exportieren Ich denke, es ist vollkommen in Ordnung ist nicht erschöpfende Muster hier zu verwenden. Sobald Sie exportieren tun, werden Sie die Kontrolle über die Eingänge verlieren und mit den fehlenden Fällen zu tun haben!