MySQL Workbench
 sql >> Datenbank >  >> Database Tools >> MySQL Workbench

Unerwünschte Auswertung in Zuweisungen in Mathematica:Warum passiert es und wie kann es während des Paketladens debuggt werden?

Abgesehen vom WB (der zur Beantwortung Ihrer Frage nicht wirklich benötigt wird) scheint das Problem eine einfache Antwort zu haben, die nur darauf basiert, wie Ausdrücke während der Aufgaben ausgewertet werden. Hier ist ein Beispiel:

In[1505]:= 
notGoodQ[x_]:=True;
Clear[g];
g[x_?notGoodQ]:=(Message[g::nogood,x];Abort[])

In[1509]:= g/:cccQ[g[x0_]]:=True

During evaluation of In[1509]:= g::nogood: -- Message text not found -- (x0_)
Out[1509]= $Aborted

Damit es funktioniert, habe ich absichtlich eine Definition für notGoodQ erstellt um immer True zurückzugeben . Nun, warum war g[x0_] bei der Zuweisung durch TagSetDelayed ausgewertet ? Die Antwort lautet, während TagSetDelayed (sowie SetDelayed ) in einer Zuweisung h/:f[h[elem1,...,elemn]]:=... wendet keine Regeln an, die f hat, wird es h[elem1,...,elem2] auswerten , sowie f . Hier ist ein Beispiel:

In[1513]:= 
ClearAll[h,f];
h[___]:=Print["Evaluated"];

In[1515]:= h/:f[h[1,2]]:=3

During evaluation of In[1515]:= Evaluated
During evaluation of In[1515]:= TagSetDelayed::tagnf: Tag h not found in f[Null]. >>
Out[1515]= $Failed  

Die Tatsache, dass TagSetDelayed ist HoldAll bedeutet nicht, dass es seine Argumente nicht auswertet - es bedeutet nur, dass die Argumente unausgewertet ankommen, und ob sie ausgewertet werden oder nicht, hängt von der Semantik von TagSetDelayed ab (was ich oben kurz beschrieben habe). Dasselbe gilt für SetDelayed , daher ist die häufig verwendete Aussage, dass es "seine Argumente nicht bewertet", nicht wörtlich richtig. Eine korrektere Aussage ist, dass es die Argumente unevaluiert empfängt und sie auf besondere Weise auswertet – nicht die rechte Seite auswertet, während für die linke Seite Kopf und Elemente ausgewertet werden, aber keine Regeln für den Kopf angewendet werden. Um dies zu vermeiden, können Sie Dinge in HoldPattern einschließen , etwa so:

Clear[g,notGoodQ];
notGoodQ[x_]:=EvenQ[x];
g[x_?notGoodQ]:=(Message[g::nogood,x];Abort[])
g/:cccQ[HoldPattern[g[x0_]]]:=True;

Das geht durch. Hier ist einige Verwendung:

In[1527]:= cccQ[g[1]]
Out[1527]= True

In[1528]:= cccQ[g[2]]
During evaluation of In[1528]:= g::nogood: -- Message text not found -- (2)
Out[1528]= $Aborted

Beachten Sie jedoch, dass HoldPattern erforderlich ist in Ihrer linken Seite, wenn Sie eine Definition vornehmen, ist oft ein Zeichen dafür, dass der Ausdruck in Ihrem Kopf auch während des Funktionsaufrufs ausgewertet werden kann, was Ihren Code beschädigen kann. Hier ist ein Beispiel dafür, was ich meine:

In[1532]:= 
ClearAll[f,h];
f[x_]:=x^2;
f/:h[HoldPattern[f[y_]]]:=y^4;

Dieser Code versucht Fälle wie h[f[something]] abzufangen , aber es wird offensichtlich seit f[something] fehlschlagen wird ausgewertet, bevor die Auswertung zu h kommt :

In[1535]:= h[f[5]]
Out[1535]= h[25]

Für mich die Notwendigkeit von HoldPattern auf der linken Seite ist ein Zeichen dafür, dass ich mein Design überdenken muss.

BEARBEITEN

In Bezug auf das Debuggen während des Ladens in WB können Sie (IIRC, kann es jetzt nicht überprüfen) die guten alten Druckanweisungen verwenden, deren Ausgabe in der WB-Konsole angezeigt wird. Ich persönlich habe selten das Bedürfnis nach einem Debugger für diesen Zweck (Debugging-Paket beim Laden)

BEARBEITEN 2

Als Antwort auf die Bearbeitung in der Frage:

In Bezug auf die Reihenfolge der Definitionen:Ja, das können Sie tun, und es löst dieses spezielle Problem. Aber im Allgemeinen ist dies nicht robust, und ich würde es nicht als eine gute allgemeine Methode betrachten. Es ist schwer, für einen konkreten Fall einen konkreten Rat zu geben, da es etwas aus dem Kontext gerissen ist, aber mir scheint, dass die Verwendung von UpValues hier ist ungerechtfertigt. Wenn dies zur Fehlerbehandlung getan wird, gibt es andere Wege um dies ohne Verwendung von UpValues zu tun .

Im Allgemeinen UpValues werden am häufigsten verwendet, um eine Funktion auf sichere Weise zu überladen, ohne der zu überladenden Funktion eine Regel hinzuzufügen. Ein Ratschlag ist, die Verknüpfung von UpValues zu vermeiden mit Köpfen, die auch DownValues haben und kann evaluieren - dadurch fangen Sie an, ein Spiel mit evaluator zu spielen, und werden schließlich verlieren. Am sichersten ist es, UpValues anzuhängen Symbole (Köpfe, Behälter) zu inertisieren, die oft einen "Typ" von Objekten darstellen, auf die Sie eine bestimmte Funktion überladen möchten.

Zu meinem Kommentar zum Vorhandensein von HoldPattern auf ein schlechtes Design hindeutet. Es gibt sicherlich sind legitime Verwendungen für HoldPattern , wie dieses (etwas künstliche):

In[25]:= 
Clear[ff,a,b,c];
ff[HoldPattern[Plus[x__]]]:={x};
ff[a+b+c]

Out[27]= {a,b,c} 

Hier ist es gerechtfertigt, weil in vielen Fällen Plus bleibt unbewertet und ist in seiner unbewerteten Form nützlich - da man daraus schließen kann, dass es eine Summe darstellt. Wir brauchen HoldPattern hier übrigens Plus auf einem einzelnen Argument definiert ist und weil ein Muster während der Definition zufällig ein einzelnes Argument ist (obwohl es im Allgemeinen mehrere Argumente beschreibt). Also verwenden wir HoldPattern hier, um zu verhindern, dass das Muster als normales Argument behandelt wird, aber dies unterscheidet sich größtenteils von den beabsichtigten Anwendungsfällen für Plus . Wann immer dies der Fall ist (wir sind sicher, dass die Definition für die beabsichtigten Anwendungsfälle gut funktioniert), HoldPattern ist gut. Beachten Sie übrigens, dass dieses Beispiel auch zerbrechlich ist:

In[28]:= ff[Plus[a]]
Out[28]= ff[a]

Der Grund, warum es meistens immer noch in Ordnung ist, ist, dass wir normalerweise Plus nicht verwenden auf einem einzigen Argument.

Aber es gibt eine zweite Gruppe von Fällen, in denen die Struktur der normalerweise gelieferten Argumente die gleiche ist wie die Struktur der Muster, die für die Definition verwendet werden. In diesem Fall zeigt die Musterauswertung während der Zuweisung an, dass die gleiche Auswertung mit tatsächlichen Argumenten während der Funktionsaufrufe erfolgen wird. Ihre Nutzung fällt in diese Kategorie. Mein Kommentar für einen Designfehler war für solche Fälle - Sie können verhindern, dass das Muster ausgewertet wird, aber Sie müssen auch verhindern, dass die Argumente ausgewertet werden, damit dies funktioniert. Und der Musterabgleich mit einem nicht vollständig ausgewerteten Ausdruck ist fragil. Außerdem sollte die Funktion niemals einige zusätzliche Bedingungen (über das hinaus, was sie typisieren kann) für die Argumente annehmen.