Wie machen Sie generische Programmierung in Haskell?

8

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?

    
obecalp 18.12.2008, 07:09
quelle

5 Antworten

27

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).

    
Daniel Earwicker 18.12.2008, 08:01
quelle
9

Wie Earwicker sagt, ist das Beispiel in Haskell nicht so aussagekräftig. Wenn du es trotzdem unbedingt haben willst, hier ist etwas ähnliches (Tausche die zwei Teile eines Paares), c & amp; p von einer interaktiven Sitzung:

%Vor%     
TheMarko 18.12.2008 08:28
quelle
6

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.

    
ja. 19.12.2008 23:21
quelle
5

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.

    
stonemetal 01.09.2009 16:35
quelle
2

Nachdem ich genug in einem Haskell-Buch gelesen habe, um Earwickers Antwort wirklich zu verstehen, würde ich vorschlagen, dass Sie auch über Klassen lesen. Ich bin mir nicht sicher, was "teilweise Spezialisierung" bedeutet, aber es klingt, als könnten sie nahe kommen.

    
Magnus 19.12.2008 22:38
quelle

Tags und Links