Die Verwendungsnachricht für Set
erinnert uns daran, dass mehrere Zuweisungen leicht über zwei Listen vorgenommen werden können, ohne dass etwas auseinander gerissen werden muss. Zum Beispiel:
Führt die Zuweisung aus und gibt Folgendes zurück:
%Vor% Thread
, das normalerweise verwendet wird, um Listen von Regeln zu generieren, kann auch explizit aufgerufen werden, um das gleiche Ergebnis zu erzielen:
Gibt:
%Vor%Wenn Sie jedoch diesen Ansatz zum Generieren von lokalisierten Konstanten verwenden, wird ein Fehler generiert. Betrachten Sie diese triviale Beispielfunktion:
%Vor%Hier die Fehlermeldung:
%Vor% In der Dokumentation der Fehlermeldung ( ref/message/With/lvw
) heißt es im Abschnitt "Weitere Informationen": " Diese Nachricht wird generiert, wenn das erste Element in With keine Liste von Zuweisungen an Symbole ist. " Angesichts dieser Erklärung verstehe ich die Mechanismen, warum meine Aufgabe fehlgeschlagen ist. Nichtsdestoweniger bin ich verwirrt und frage mich, ob dies eine notwendige Einschränkung durch die WRI oder eine geringfügige Designaufsicht ist, die gemeldet werden sollte.
Hier ist meine Frage:
Kann jemand dieses Verhalten beleuchten und / oder einen Workaround anbieten? Ich experimentierte mit dem Versuch, Evaluation
zu erzwingen, ohne Glück und ich bin mir nicht sicher, was ich noch versuchen sollte.
Was Sie anfordern, ist knifflig. Dies ist ein Job für Makros, wie bereits von den anderen veröffentlicht. Ich werde eine andere Möglichkeit erkunden - die gleichen Symbole zu verwenden, aber einige Wrapper um den Code, den Sie schreiben möchten, zu legen. Der Vorteil dieser Technik ist, dass der Code "lexikalisch" und zur "Kompilierzeit" anstatt zur Laufzeit (wie in den anderen Antworten) transformiert wird. Dies ist im Allgemeinen sowohl schneller als auch einfacher zu debuggen.
Also, hier ist eine Funktion, die das With
mit Ihrer vorgeschlagenen Syntax transformieren würde:
Beachten Sie, dass dies für den gehaltenen Code gilt. Dies hat den Vorteil, dass wir uns keine Gedanken über eine mögliche Auswertung des Codes machen müssen, weder am Anfang noch wenn expandWith
beendet ist. So funktioniert es:
Dies ist jedoch nicht sehr bequem zu verwenden. Hier ist eine Komfortfunktion, um dies zu vereinfachen:
%Vor%Wir können es jetzt als verwenden:
%Vor% Um die Erweiterung im Code zu ermöglichen, müssen Sie also einfach ew
umschließen. Hier ist Ihr Fall für die Definition der Funktion:
Wir überprüfen jetzt und sehen, dass wir eine erweiterte Definition erhalten:
%Vor% Der Vorteil dieses Ansatzes besteht darin, dass Sie ew
um einen beliebig großen Teil Ihres Codes wickeln können. Was passiert, ist, dass zuerst erweiterter Code daraus generiert wird, als ob Sie ihn selbst schreiben würden, und dann wird dieser Code ausgeführt. Für den Fall von Funktionsdefinitionen, wie f
oben, können wir sagen, dass die Codegenerierung zur "Kompilierungszeit" stattfindet, so dass Sie bei der späteren Verwendung der Funktion keinen Laufzeitaufwand vermeiden, der beim Aufruf der Funktion erheblich sein kann oft.
Ein weiterer Vorteil dieses Ansatzes ist seine Zusammensetzbarkeit: Sie können viele Syntaxerweiterungen erstellen und für jede eine ähnliche Funktion wie ew
schreiben. Wenn diese benutzerdefinierten Funktionen zur Codeumwandlung nicht miteinander kollidieren, können Sie sie einfach zusammensetzen (verschachteln), um einen kumulativen Effekt zu erzielen. In gewisser Weise erstellen Sie auf diese Weise einen benutzerdefinierten Codegenerator, der einen gültigen Mathematica-Code aus einigen Mathematica-Ausdrücken generiert, die Programme in Ihrer benutzerdefinierten Sprache darstellen, die Sie in Mathematica mit diesen Mitteln erstellen können.
BEARBEITEN
Beim Schreiben von expandWith
habe ich eine iterative Regelanwendung verwendet, um den Umgang mit der Bewertungssteuerung zu vermeiden, was ein Chaos sein kann. Für diejenigen, die daran interessiert sind, gibt es hier eine Version, die mit nicht evaluierten Code-Stücken arbeitet.
Ich finde es jedoch wesentlich komplizierter als das erste.
Das heikle Problem besteht darin, das erste Argument von Set unevaluated beizubehalten. Hier ist mein Vorschlag (offen für Verbesserungen natürlich):
%Vor%führt zu
%Vor%Inspiriert durch Halirutan unten denke ich, dass seine Lösung, die etwas sicherer gemacht wurde, dem obigen entspricht:
%Vor%Das Tutorial "LocalConstants" sagt
Der Weg mit [{x = Tiefgestellt [x, 0], ...}, Körper] funktioniert, um Körper zu nehmen und jeden zu ersetzen Vorkommen von x, usw. in ihm durch Tiefstellung [x, 0], usw. Sie können sich vorstellen mit With als a Verallgemeinerung des /. Operator, geeignet für die Anwendung auf Mathematica-Code anstelle von andere Ausdrücke.
Mit Bezug auf diese Erklärung scheint es offensichtlich, dass etwas wie
%Vor%funktioniert nicht wie erwartet in der With-Notation.
Nehmen wir an, Sie wollen wirklich damit herumhacken. With[]
hat das Attribut HoldAll, daher wird alles, was Sie als erster Parameter angeben, nicht ausgewertet. Um eine solche Vektorzuweisung zu erstellen, müssten Sie
aus der Vektornotation. Leider
%Vor%funktioniert nicht, weil das Argument für Thread nicht gehalten wird und die Zuweisung ausgewertet wird, bevor Thread etwas tun kann.
Lässt das reparieren
%Vor%gibt
%Vor% Was zunächst vielversprechend aussieht, hat das Problem nur ein bisschen verschoben. Um dies in With[]
zu verwenden, müssen Sie das mySet irgendwann durch das reale Set ersetzen. Genau dann sieht With[]
nicht die Liste {a = 1, b = 2, c = 3} sondern, da es ausgewertet werden muss, das Ergebnis aller Zuweisungen
Es scheint nicht einfach zu sein und es gibt eine zweite Frage: Wenn es einen Weg gibt um diese Einschränkung, ist es so schnell wie With oder würden wir den Geschwindigkeitsvorteil gegenüber Modul verlieren? Und wenn Geschwindigkeit nicht so wichtig ist, warum nicht Modul oder Block an erster Stelle?
Tags und Links wolfram-mathematica function localization