Frage

In Andrew Koenig eine Anekdote über Typinferenz ML verwendet der Autor Implementierung von für ML Art als Lernübung fusionieren und freut sich, ein finden „falsch“ Typinferenz.

  

Zu meiner großen Überraschung, der Compiler berichtete eine Art

'a list -> int list
     

Mit anderen Worten, diese Sortierfunktion akzeptiert eine Liste von jeder Art überhaupt und gibt eine Liste von ganzen Zahlen.

     

Das ist unmöglich. Der Ausgang muss eine Permutation der Eingabe sein; wie kann es möglicherweise eine andere Art haben? Der Leser wird sicherlich meinen ersten Impuls vertraut finden: Ich fragte mich, ob ich einen Fehler im Compiler aufgedeckt hatte

     

darüber etwas mehr Nach einigem Nachdenken erkannte ich, dass es eine andere Art und Weise war, in der die Funktion ihr Argument ignorieren könnte: vielleicht manchmal ist es gar nicht zurück. Ja, als ich es versuchte, das ist genau das, was passiert ist. sort(nil) haben nil zurück, aber jede nicht-leere Liste Sortierung in eine unendliche Rekursion Schleife gehen würde

Wenn übersetzt Haskell

split [] = ([], [])
split [x] = ([x], [])
split (x:y:xs) = (x:s1, y:s2)
  where (s1,s2) = split xs

merge xs [] = xs
merge [] ys = ys
merge xx@(x:xs) yy@(y:ys)
  | x < y     = x : merge xs yy
  | otherwise = y : merge xx ys

mergesort [] = []
mergesort xs = merge (mergesort p) (mergesort q)
  where (p,q) = split xs

GHC folgert eine ähnliche Art:

*Main> :t mergesort
mergesort :: (Ord a) => [t] -> [a]

Wie funktioniert die Damas-Hindley-Milner-Algorithmus dieser Art schließen ?

War es hilfreich?

Lösung

Dies ist in der Tat ein bemerkenswertes Beispiel; eine unendliche Schleife erkannt wird, im Wesentlichen in kompilieren Zeit ! Es ist nichts Besonderes über die Hindley-Milner-Inferenz in diesem Beispiel; es geht nur wie üblich.

Beachten Sie, dass ghc die Arten von split und merge bekommt richtig:

*Main> :t split
split :: [a] -> ([a], [a])
*Main> :t merge
merge :: (Ord t) => [t] -> [t] -> [t]

Nun, wenn es um mergesort kommt, ist es in der Regel eine Funktion t 1 → t 2 für einige Typen t 1 und t 2 . Dann sieht er die erste Zeile:

mergesort [] = []

und erkennt, dass t 1 und t 2 muss Listentypen sein, sagt t 1 = [t 3 ] und t 2 = [t 4 ]. So muss mergesort eine Funktion sein [t 3 ] → [t 4 ]. Die nächste Zeile

mergesort xs = merge (mergesort p) (mergesort q) 
  where (p,q) = split xs

sagt, dass:

  • xs muss ein Eingang zu spalten, das heißt, vom Typ [A] für ein a (was es ohnehin schon ist, für a = t 3 ).
  • So p und q sind ebenfalls vom Typ [t 3 ], da split ist [a] → ([a], [a])
  • mergesort p daher (man erinnere sich, dass mergesort angenommen wird vom Typ sein [t 3 ] → [t 4 ]) vom Typ [t 4 ].
  • mergesort q ist vom Typ [t 4 ] für genau den gleichen Grund.
  • AS merge hat (Ord t) => [t] -> [t] -> [t] eingeben, und die Eingänge in der Expression merge (mergesort p) (mergesort q) sind beide vom Typ [t 4 ], der Typ t 4 muss in Ord werden.
  • Schließlich ist die Art der merge (mergesort p) (mergesort q) dieselben wie beide seiner Eingänge, nämlich [t 4 ]. Das paßt mit der bisher bekannten Art [t 3 ] → [t 4 ] für mergesort, so gibt es keine mehr Schlüsse und die "Vereinigung" Teil der getan werden Hindley-Milner-Algorithmus ist abgeschlossen. mergesort ist vom Typ [t 3 ] → [t 4 ] mit t 4 in Ord.

Das ist, warum Sie bekommen:

*Main> :t mergesort 
mergesort :: (Ord a) => [t] -> [a]

(Die obige Beschreibung in Bezug auf die logische Folgerung ist, entspricht dem, was der Algorithmus tut, aber die spezifische Abfolge von Schritten der Algorithmus folgt, ist einfach, dass zum Beispiel auf der Wikipedia-Seite angegeben.)

Andere Tipps

können Diese Art abgeleitet werden, weil sie sieht, dass Sie das Ergebnis der mergesort merge passieren, was wiederum die Köpfe der Listen mit < vergleicht, die einen Teil des Ord ist typeclass. So ist die Typinferenz kann vermuten, dass es eine Liste von einer Instanz von Ord zurückkehren. Natürlich, da es tatsächlich unendlich recurses, können wir nichts anderes über die Art schließen es nicht tatsächlich zurück.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top