28

Dies ist ein Follow-up von Why am I getting "Non-exhaustive patterns in function..." when I invoke my Haskell substring function?Warum sind nicht erschöpfende Muster in Haskell keine Kompilierungsfehler?

ich, dass mit -Wall verstehen, GHC gegen nicht-erschöpfende Muster warnen. Ich frage mich, was ist der Grund für das nicht einen Fehler bei der Kompilierung von Standard machen gegeben, 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 einen Haskell Compiler auszuführen, diese Art von Analyse erzwingen wollte?
  • eine nicht erschöpfende Mustersuche kann einige, aber nicht alle Fälle finden?
  • teilweise definierte Funktionen werden als legitim angesehen und häufig genug verwendet, um die oben gezeigte Art von Konstrukt nicht aufzuerlegen? Wenn dies der Fall ist, können Sie mir erklären, warum nicht erschöpfende Muster hilfreich/legitim sind?

Antwort

33

Es gibt Fälle, in denen es Ihnen nichts ausmacht, dass eine Musterübereinstimmung nicht erschöpfend ist. Zum Beispiel, während dies nicht die optimale Umsetzung sein könnte, 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 erschöpfendes (negative Zahlen haben jeden Fall nicht übereinstimmen) ist für die typische Verwendung der Fakultät keine Rolle.

Auch könnte es im allgemeinen nicht möglich sein, für den Compiler zu entscheiden, ob ein Mustervergleich erschöpfend ist:

mod2 :: Integer -> Integer 
mod2 n | even n = 0 
mod2 n | odd n = 1 

Hier werden alle Fälle abgedeckt werden sollten, aber der Compiler wahrscheinlich nicht erkennen kann. Da die Wächter beliebig komplex sein können, kann der Compiler nicht immer entscheiden, ob die Muster vollständig sind. Natürlich wäre dieses Beispiel besser mit otherwise geschrieben, aber ich denke, es sollte auch in seiner jetzigen Form kompilieren.

+4

Ein weiterer etwas häufiger Fall wäre Lambda-Anweisungen innerhalb einer Wache/Fall/wenn Zweig. Sie wissen, dass das Argument eine bestimmte Form hat, aufgrund welcher Branche Sie sich befinden, also ist es unnötig, es in das Lambda aufzunehmen. –

+1

Ich denke nicht, dass es anders geschrieben werden sollte. Es ist eine großartige Mod2-Definition, auch wenn der Compiler denkt, dass es nicht exahus ist. Ich kam zu dieser Frage, weil ich diesen Fehler bekam, der eine Fib-Funktion schreibt, die für negative ganze Zahlen nicht definiert werden sollte. –

+0

vielleicht ist dies nicht möglich, aber entscheidet, ob eine Musterübereinstimmung vollständig ist oder nicht mit dem Anhalteproblem zusammenhängt? intuitiv scheint es, als würde eine Sprache, die so streng typisiert ist wie Haskell, diese Art der Analyse zumindest für Teilmengen der Sprache ermöglichen, aber ich weiß, dass Bauchgefühl normalerweise eine schreckliche Möglichkeit ist, zu erraten, ob etwas berechenbar ist oder nicht. – kai

12

Sie können -Werror verwenden, um Warnungen in Fehler zu verwandeln. Ich weiß nicht, ob Sie nur die nicht erschöpfenden Musterwarnungen in Fehler umwandeln können, sorry!

Was den dritten Teil Ihrer Frage:

ich manchmal eine Reihe von Funktionen schreiben, die eng zusammenarbeiten, neigen und haben Eigenschaften, die man nicht so leicht in Haskell ausdrücken kann. Zumindest einige dieser Funktionen neigen dazu, nicht erschöpfende Muster aufzuweisen, üblicherweise die "Konsumenten". Dies kommt zum Beispiel bei Funktionen vor, die einander invers sind.

Ein Spielzeug Beispiel:

duplicate :: [a] -> [a] 
duplicate [] = [] 
duplicate (x:xs) = x : x : 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 Zahl sind von Elementen oder 2 aufeinanderfolgenden Elementen unterscheiden sich. Wenn es nicht abstürzt, ist es, weil bs in erster Linie von produziert wurde (oder von duplicate produziert worden sein könnte!).

So haben wir die folgenden Gesetze (nicht gültig Haskell):

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

Nun, wenn Sie hier nicht erschöpfende Muster verhindern möchten, können Sie removeDuplicates return Maybe [a], oder fügen Sie Fehlermeldungen für die Vermissten Fälle. Man könnte sogar etwas entlang der Linien von

newtype DuplicatedList a = DuplicatedList [a] 

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

tut All dies notwendig ist, weil man nicht einfach ausdrücken kann ‚eine Liste von gleicher Länge sein, mit aufeinanderfolgenden Paaren von Elementen gleiche Bedingungen‘ in dem Haskell Typ-System (es sei denn, du bist Oleg :)

Aber wenn Sie nicht exportieren removeDuplicates Ich denke, es ist völlig in Ordnung, hier nicht erschöpfende Muster zu verwenden. Sobald Sie es exportieren, verlieren Sie die Kontrolle über die Eingaben und müssen sich mit den fehlenden Fällen befassen!

+0

Ich denke du meinst removeDuplicates (x: y: xs) | x == y = x: removeDupliziert xs. – gawi

+0

Danke, ich habe es repariert! – yatima2975

Verwandte Themen