Frage Mathematica: Was ist symbolische Programmierung?


Ich bin ein großer Fan von Stephen Wolfram, aber er ist definitiv nicht scheu vor seinem eigenen Horn. In vielen Referenzen preist er Mathematica als ein anderes symbolisches Programmierparadigma. Ich bin kein Mathematica-Benutzer.

Meine Fragen sind: Was ist das symbolische Programmieren? Und wie vergleicht es sich mit funktionalen Sprachen (wie Haskell)?


76
2017-12-13 16:28


Ursprung


Antworten:


Sie können sich die symbolische Programmierung von Mathematica als ein Such- und Ersetzungssystem vorstellen, in dem Sie programmieren, indem Sie Such- und Ersetzungsregeln festlegen.

Zum Beispiel könnten Sie die folgende Regel angeben

area := Pi*radius^2;

Das nächste Mal, wenn Sie verwenden areaEs wird ersetzt durch Pi*radius^2. Angenommen, Sie definieren eine neue Regel

radius:=5

Jetzt, wann immer du benutzt radius, es wird in neu geschrieben werden 5. Wenn Sie auswerten area es wird neu geschrieben werden Pi*radius^2 welches die Regel für das Umschreiben auslöst radius und du wirst es bekommen Pi*5^2 als Zwischenergebnis. Dieses neue Formular löst eine integrierte Rewriting-Regel für aus ^ Operation, damit der Ausdruck weiter umgeschrieben wird Pi*25. An diesem Punkt wird das Neuschreiben beendet, da keine anwendbaren Regeln vorhanden sind.

Sie können funktionale Programmierung emulieren, indem Sie Ihre Ersetzungsregeln als Funktion verwenden. Wenn Sie beispielsweise eine Funktion definieren möchten, die hinzugefügt werden soll, können Sie dies tun

add[a_,b_]:=a+b

Jetzt add[x,y] wird neu geschrieben x+y. Wenn Sie möchten, dass Add nur für numerische a, b angewendet wird, können Sie stattdessen tun

add[a_?NumericQ, b_?NumericQ] := a + b

Jetzt, add[2,3] wird neu geschrieben 2+3 Verwenden Sie Ihre Regel und dann in 5 Verwenden der integrierten Regel für +, wohingegen add[test1,test2] bleibt unverändert.

Hier ist ein Beispiel für eine interaktive Ersetzungsregel

a := ChoiceDialog["Pick one", {1, 2, 3, 4}]
a+1

Hier, a wird ersetzt mit ChoiceDialog, die dann durch die Zahl ersetzt wird, die der Benutzer im Popup-Dialogfeld ausgewählt hat, wodurch beide Größen numerisch werden und die Ersatzregel ausgelöst wird +. Hier, ChoiceDialog als eine eingebaute Ersetzungsregel in der Art von "Ersetze ChoiceDialog [einige Sachen] mit dem Wert der Schaltfläche, auf die der Benutzer geklickt hat".

Regeln können unter Verwendung von Bedingungen definiert werden, die selbst Regeln durchlaufen müssen, um zu produzieren True oder False. Nehmen wir einmal an, Sie haben eine neue Gleichungslösungsmethode erfunden, aber Sie denken, dass sie nur funktioniert, wenn das Endergebnis Ihrer Methode positiv ist. Du könntest die folgende Regel machen

 solve[x + 5 == b_] := (result = b - 5; result /; result > 0)

Hier, solve[x+5==20] wird mit 15 ersetzt, aber solve[x + 5 == -20] ist unverändert, da keine Regel zutrifft. Die Bedingung, die die Anwendung dieser Regel verhindert, ist /;result>0. Der Evaluator sieht im Wesentlichen die potenzielle Ausgabe der Regelanwendung, um zu entscheiden, ob er mit der Regel weitermachen soll.

Mathematicas Evaluator überschreibt gierig jedes Muster mit einer der Regeln, die für dieses Symbol gelten. Manchmal möchten Sie eine feinere Kontrolle haben und in diesem Fall könnten Sie Ihre eigenen Regeln definieren und diese manuell anwenden

myrules={area->Pi radius^2,radius->5}
area//.myrules

Dies wird Regeln anwenden, die in definiert sind myrules bis das Ergebnis aufhört sich zu ändern. Dies ist dem Standard-Evaluator ziemlich ähnlich, aber jetzt könnten Sie mehrere Regelwerke haben und diese selektiv anwenden. Ein fortgeschrittener Beispiel zeigt, wie ein Prolog-ähnlicher Evaluator erstellt wird, der über Sequenzen von Regelanwendungen sucht.

Ein Nachteil der aktuellen Mathematica-Version besteht darin, dass Sie Mathematicas Standard-Evaluator verwenden müssen Integrate, Solve, etc) und möchte die Standardsequenz der Auswertung ändern. Das ist aber möglich kompliziert, und ich denke gerne, dass eine zukünftige Implementierung der symbolischen Programmierung einen eleganteren Weg haben wird, die Bewertungssequenz zu kontrollieren


70
2017-12-13 22:12



Wenn ich den Ausdruck "symbolische Programmierung" höre, fallen mir sofort LISP, Prolog und (ja) Mathematica ein. Ich würde eine symbolische Programmierumgebung als eine charakterisieren, in der die Ausdrücke, die verwendet werden, um Programmtext darzustellen, zufällig auch die primäre Datenstruktur sind. Als Ergebnis wird es sehr einfach, Abstraktionen auf Abstraktionen aufzubauen, da Daten leicht in Code und umgekehrt umgewandelt werden können.

Mathematica nutzt diese Fähigkeit stark aus. Noch stärker als LISP und Prolog (IMHO).

Betrachten Sie als Beispiel für die symbolische Programmierung die folgende Abfolge von Ereignissen. Ich habe eine CSV-Datei, die wie folgt aussieht:

r,1,2
g,3,4

Ich habe diese Datei gelesen in:

Import["somefile.csv"]
--> {{r,1,2},{g,3,4}}

Ist das Ergebnis Daten oder Code? Es ist beides. Es sind die Daten, die beim Lesen der Datei entstehen, aber es ist auch der Ausdruck, der diese Daten erzeugt. Wie der Code sagt, ist dieser Ausdruck jedoch inert, da das Ergebnis seiner Bewertung einfach er selbst ist.

Jetzt wende ich eine Transformation an das Ergebnis an:

% /. {c_, x_, y_} :> {c, Disk[{x, y}]}
--> {{r,Disk[{1,2}]},{g,Disk[{3,4}]}}

Ohne auf die Details einzugehen, ist nur das passiert Disk[{...}] wurde um die letzten zwei Zahlen von jeder Eingabezeile gewickelt. Das Ergebnis ist immer noch Daten / Code, aber immer noch inert. Eine weitere Transformation:

% /. {"r" -> Red, "g" -> Green}
--> {{Red,Disk[{1,2}]},{Green,Disk[{3,4}]}}

Ja, immer noch inert. Durch ein merkwürdiges Zusammentreffen ist dieses letzte Ergebnis jedoch zufällig eine Liste gültiger Anweisungen in Mathematicas integrierter domänenspezifischer Sprache für Grafiken. Eine letzte Transformation, und die Dinge beginnen zu passieren:

% /. x_ :> Graphics[x]
--> Graphics[{{Red,Disk[{1,2}]},{Green,Disk[{3,4}]}}]

Eigentlich würden Sie dieses letzte Ergebnis nicht sehen. In einer epischen Darstellung von syntaktischem Zucker würde Mathematica dieses Bild von roten und grünen Kreisen zeigen:

alt text

Aber der Spaß hört hier nicht auf. Unter all dem syntaktischen Zucker haben wir immer noch einen symbolischen Ausdruck. Ich kann eine andere Transformationsregel anwenden:

% /. Red -> Black

alt text

Presto! Der rote Kreis wurde schwarz.

Es ist diese Art von "Symboldrücken", die die symbolische Programmierung kennzeichnet. Eine große Mehrheit der Mathematica-Programmierung ist von dieser Art.

Funktional vs. Symbolisch

Ich werde die Unterschiede zwischen symbolischer und funktionaler Programmierung nicht im Detail ansprechen, aber ich werde einige Bemerkungen beisteuern.

Man könnte symbolische Programmierung als eine Antwort auf die Frage ansehen: "Was würde passieren, wenn ich alles nur mit Ausdruckstransformationen modellieren würde?" Funktionale Programmierung kann dagegen als eine Antwort auf Folgendes angesehen werden: "Was würde passieren, wenn ich versuchen würde, alles nur mit Funktionen zu modellieren?" Wie bei der symbolischen Programmierung erleichtert die funktionale Programmierung das schnelle Erstellen von Schichten von Abstraktionen. Das Beispiel, das ich hier gegeben habe, könnte leicht in, sagen wir, Haskell mit einem funktionalen reaktiven Animationsansatz reproduziert werden. Bei der funktionalen Programmierung geht es um Funktionszusammensetzung, Funktionen auf höherer Ebene, Kombinatoren - all die raffinierten Dinge, die Sie mit Funktionen tun können.

Mathematica ist eindeutig für die symbolische Programmierung optimiert. Es ist möglich, Code in funktionalem Stil zu schreiben, aber die funktionalen Merkmale in Mathematica sind wirklich nur ein dünner Anstrich über Transformationen (und eine undichte Abstraktion dabei, siehe Fußnote unten).

Haskell ist eindeutig für die funktionale Programmierung optimiert. Es ist möglich, Code im symbolischen Stil zu schreiben, aber ich würde das streiten syntaktisch Die Darstellung von Programmen und Daten ist sehr unterschiedlich und macht die Erfahrung suboptimal.

Abschließende Bemerkungen

Abschließend befürworte ich, dass es eine Unterscheidung zwischen funktionaler Programmierung (wie sie von Haskell verkörpert wird) und symbolischer Programmierung (wie von Mathematica verkörpert) gibt. Ich denke, wenn man beides studiert, dann wird man wesentlich mehr lernen, als nur eines zu lernen - der ultimative Test der Unterscheidbarkeit.


Leaky Functional Abstraction in Mathematica?

Yup, undicht. Versuchen Sie dies zum Beispiel:

f[x_] := g[Function[a, x]];
g[fn_] := Module[{h}, h[a_] := fn[a]; h[0]];
f[999]

Dilly berichtete und wurde von der WRI bestätigt. Die Antwort: Vermeiden Sie die Verwendung von Function[var, body] (Function[body] es ist okay).


72
2017-12-14 03:54



Wie andere bereits erwähnt haben, macht Mathematica eine Menge Überschreibung von Termen. Vielleicht ist Haskell nicht der beste Vergleich, aber Rein ist eine nette funktionale Umschreibungssprache (die Leuten mit einem Haskell-Hintergrund vertraut vorkommen sollte). Vielleicht wird das Lesen ihrer Wiki-Seite zum Umschreiben von Begriffen ein paar Dinge für Sie klären:

http://code.google.com/p/pure-lang/wiki/Rewriting


9
2017-12-14 09:37



Mathematica verwendet das Umschreiben von Termen sehr stark. Die Sprache bietet eine spezielle Syntax für verschiedene Formen des Umschreibens, spezielle Unterstützung für Regeln und Strategien. Das Paradigma ist nicht so "neu" und natürlich ist es nicht einzigartig, aber sie sind definitiv auf dem neuesten Stand dieser "symbolischen Programmierung", zusammen mit den anderen starken Spielern wie Axiom.

Was den Vergleich mit Haskell anbelangt, könnte man es mit ein wenig Hilfe aus der Textbausteinbibliothek umschreiben, aber es ist nicht annähernd so einfach wie in einem dynamisch typisierten Mathematica.


5
2017-12-13 18:23