Aus C ++ kommend finde ich generische Programmierung unentbehrlich. Ich frage mich, wie sich die Leute in Haskell nähern?
Wie schreibt man generische Swap-Funktionen in Haskell?
Gibt es ein äquivalentes Konzept der partiellen Spezialisierung in Haskell?
In C ++ kann ich die generische Auslagerungsfunktion teilweise spezialisieren, mit einem speziellen für einen generischen map / hash_map-Container, der eine spezielle Auslagerungsmethode für O (1) -Containeraustausch hat. Wie macht man das in Haskell oder was ist das kanonische Beispiel für generische Programmierung in Haskell?
Dies hängt eng mit Ihrer anderen Frage zu Haskell und Quicksort zusammen. Ich denke, Sie müssen wahrscheinlich mindestens die Einführung eines Buches über Haskell lesen. Es hört sich so an, als ob Sie noch nicht den entscheidenden Punkt verstanden haben, der Ihnen verbietet, die Werte bestehender Variablen zu verändern.
Swap (wie in C ++ verstanden und verwendet) ist von Natur aus alles, um bestehende Werte zu modifizieren. So können wir einen Namen verwenden, um auf einen Container zu verweisen und diesen Container durch völlig andere Inhalte ersetzen, und diesen Vorgang für bestimmte Container so schnell (und ausnahmslos) spezialisieren, dass wir einen Modify-and-Publish-Ansatz implementieren können (wichtig für das Schreiben von ausnahmesicherem Code oder den Versuch, lockfreien Code zu schreiben).
Sie können einen generischen Tausch in Haskell schreiben, aber es würde wahrscheinlich ein Paar Werte nehmen und ein neues Paar zurückgeben, das die gleichen Werte mit umgekehrten Positionen oder etwas ähnliches enthält. Nicht wirklich dasselbe und nicht die gleichen Anwendungen. Es würde keinen Sinn machen, es für eine Map zu spezialisieren, indem man innerhalb dieser Map gräbt und seine individuellen Membervariablen vertauscht, weil man solche Dinge in Haskell einfach nicht machen darf (man kann die Spezialisierung machen, aber nicht das Ändern von Variablen).
Angenommen, wir wollten eine Liste in Haskell "messen":
%Vor% Das ist eine Typdeklaration. Dies bedeutet, dass die Funktion measure
eine Liste von allem benötigt ( a
ist ein generischer Typparameter, da er mit einem Kleinbuchstaben beginnt) und gibt eine Ganzzahl zurück. Das funktioniert also für eine Liste beliebiger Elementtypen - das wäre eine Funktionsschablone in C ++ oder eine polymorphe Funktion in Haskell (nicht dasselbe wie eine polymorphe Klasse in C ++).
Wir können dies jetzt definieren, indem wir für jeden interessanten Fall Spezialisierungen bereitstellen:
%Vor%d. messen Sie die leere Liste und Sie erhalten Null.
Hier ist eine sehr allgemeine Definition, die alle anderen Fälle abdeckt:
%Vor%Das Bit in Klammern auf der LHS ist ein Muster. Es bedeutet: nimm eine Liste, breche den Kopf ab und nenne ihn h, nenne den restlichen Teil r. Diese Namen sind dann Parameter, die wir verwenden können. Dies entspricht einer Liste mit mindestens einem Element.
Wenn Sie versucht haben, Template-Metaprogrammierung in C ++ durchzuführen, dann ist das alles ein alter Hut für Sie, weil es genau den gleichen Stil beinhaltet - Rekursion, um Schleifen zu machen, Spezialisierung, um die Rekursion zu beenden. Außer in Haskell funktioniert es zur Laufzeit (Spezialisierung der Funktion für bestimmte Werte oder Muster von Werten).
In Haskell sind Funktionen so generisch (polymorph) wie möglich - der Compiler wird auf den "allgemeinsten Typ" schließen. Zum Beispiel ist der Beispiel-Swap von TheMarko in Ermangelung einer Typsignatur standardmäßig polymorph:
* Haupt & gt; lass tauschen (a, b) = (b, a)
* Haupt & gt; : t tauschen
Tauschen :: (t, t1) - & gt; (t1, t)
Wie bei der teilweisen Spezialisierung hat ghc eine Nicht-98-Erweiterung:
Datei: /// C: /ghc/ghc-6.10.1/doc/users_guide/pragmas.html#specialize-pragma
Beachten Sie auch, dass die Terminologie nicht übereinstimmt. Was in C ++, Java und C # als generisch bezeichnet wird, wird in Haskell als polymorph bezeichnet. "Generisch" bedeutet in Haskell meist polytypisch:
Ссылка
Aber, ich benutze die c ++ Bedeutung von generic.
In Haskell würden Sie Typklassen erstellen. Typklassen sind nicht wie Klassen in OO-Sprachen. Nehmen Sie die Klasse Numeric type Es besagt, dass alles, was eine Instanz der Klasse ist, bestimmte Operationen (+ - * /) ausführen kann, so dass Integer ein Mitglied von Numeric ist und Implementierungen der Funktionen bereitstellt, die als Numerisch betrachtet werden müssen und überall verwendet werden können Numerisch wird erwartet.
Sagen wir, du möchtest Ints und Strings footieren können. Dann würden Sie Int und String zu sein deklarieren Instanzen der Typklasse Foo. Jetzt wo Sie den Typ (Foo a) sehen, können Sie jetzt Int oder String verwenden.
Der Grund, warum Sie ints und floats nicht direkt hinzufügen können, ist, dass add den Typ (Numerisch a) a - & gt; a - & gt; a a ist eine Typvariable und genau wie reguläre Variablen kann sie nur einmal gebunden werden. Sobald Sie sie an Int binden, muss jedes a in der Liste Int sein.
Tags und Links haskell generic-programming