Unerwünschte Auswertung in Zuweisungen in Mathematica: Warum passiert es und wie debugge ich es während des Paketladens?

8

Ich entwickle ein (großes) Paket, das nicht mehr richtig lädt. Dies geschah, nachdem ich eine einzelne Codezeile geändert hatte. Wenn ich versuche, das Paket zu laden (mit Needs), beginnt das Paket zu laden und dann wird eine der gesetzten Definitionen "lebendig" (dh wird irgendwie ausgewertet), wird in einer Fehler-Trapping-Routine gefangen einige Zeilen vor und das Paket gefangen Ladeabbrüche.
Die Fehler-Trapping-Routine mit Abbruch führt ihre Aufgabe aus, mit der Ausnahme, dass sie während der Paket-Ladephase nicht an erster Stelle aufgerufen worden sein sollte. Die Fehlermeldung zeigt, dass das falsche Argument tatsächlich ein Musterausdruck ist, den ich ein paar Zeilen später auf den Zeilen einer festgelegten Verzögerungsdefinition verwende.

In etwa so:

%Vor%

Wenn ich versuche, das Paket zu laden, bekomme ich:

%Vor%

Wie Sie sehen, ist das übergebene Argument ein Muster und kann nur von der obigen Codezeile kommen.

Ich habe versucht, den Grund für dieses Verhalten zu finden, aber bisher war ich nicht erfolgreich. Also entschied ich mich, die leistungsstarken Workbench-Debugging-Tools zu verwenden.

Ich möchte Schritt für Schritt (oder mit Haltepunkten) sehen, was passiert, wenn ich das Paket lade. Ich bin noch nicht zu vertraut mit WB, aber es scheint, dass mit Debug als ..., das Paket zuerst geladen und dann schließlich mit Haltepunkten, ect debugged. Mein Problem ist, dass das Paket nicht einmal komplett geladen wird! Und jeder Haltepunkt, der vor dem Laden des Pakets gesetzt wurde, scheint nicht effektiv zu sein.

Also ... 2 Fragen:

  1. kann jemand bitte erklären, warum diese Codezeilen während des Paketladens "lebendig werden"? (Es gibt keine offensichtlichen Syntaxfehler oder Code-Fragmente, die in dem Paket verbleiben, soweit ich das sehen kann)
  2. kann jemand bitte erklären, wie (wenn) es möglich ist, zu untersuchen / zu debuggen Paketcode beim Laden in WB?

Danke für jede Hilfe.

Bearbeiten

Angesichts Leonids Antwort und unter Verwendung seines EvenQ-Beispiels: Wir können die Verwendung von Holdpattern vermeiden, indem wir einfach Werte für g BEFORE downvalues ​​für g

definieren %Vor%

Jetzt

%Vor%

während

%Vor%

Also ... allgemeine Regel:

Wenn Sie eine Funktion g schreiben, definieren Sie zuerst die upvalues ​​für g und dann die downvalues ​​für g, ansonsten verwenden Sie Holdpattern

Können Sie diese Regel abonnieren?

Leonid sagt, dass die Verwendung von Holdpattern möglicherweise auf verbesserbares Design hindeutet. Wie könnte man neben der oben angegebenen Lösung das Design des obigen kleinen Codes verbessern oder, besser gesagt, im Allgemeinen, wenn es um Upwerte geht?

Danke für Ihre Hilfe

    
magma 13.09.2011, 20:51
quelle

1 Antwort

12

Abgesehen von der WB (die nicht wirklich benötigt wird, um Ihre Frage zu beantworten), scheint das Problem eine einfache Antwort zu haben, die nur darauf basiert, wie Ausdrücke bei Zuweisungen bewertet werden. Hier ist ein Beispiel:

%Vor%

Damit es funktioniert, habe ich bewusst eine Definition für notGoodQ gemacht, um immer True zurückzugeben. Nun, warum wurde g[x0_] während der Zuweisung durch TagSetDelayed ausgewertet? Die Antwort lautet: Während TagSetDelayed (sowie SetDelayed ) in einer Zuweisung h/:f[h[elem1,...,elemn]]:=... keine Regeln anwendet, die f haben könnte, wird h[elem1,...,elem2] sowie f ausgewertet. Hier ist ein Beispiel:

%Vor%

Die Tatsache, dass TagSetDelayed HoldAll ist, bedeutet nicht, dass sie ihre Argumente nicht auswertet - es bedeutet nur, dass die Argumente unausgewertet ankommen und ob sie ausgewertet werden oder nicht, hängt von der Semantik von% co_de ab % (was ich oben kurz beschrieben habe). Dasselbe gilt für TagSetDelayed . Daher ist die häufig verwendete Anweisung, dass sie "ihre Argumente nicht auswertet", nicht wirklich korrekt. Eine korrektere Aussage ist, dass sie die unausgewerteten Argumente erhält und sie auf eine spezielle Weise auswertet - nicht die r.h.s auswerten, während für l.h.s. Kopf und Elemente auswerten, aber keine Regeln für den Kopf anwenden. Um dies zu vermeiden, können Sie Dinge wie folgt in SetDelayed einschließen:

%Vor%

Das geht durch. Hier ist eine Verwendung:

%Vor%

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

%Vor%

Dieser Code versucht Fälle wie HoldPattern zu erfassen, aber es wird offensichtlich fehlschlagen, da h[f[something]] auswertet, bevor die Auswertung zu f[something] kommt:

%Vor%

Für mich ist die Notwendigkeit von h auf dem l.h.s. ist ein Zeichen, dass ich mein Design überdenken muss.

BEARBEITEN

Was das Debugging während des Ladens in WB betrifft, kann man (IIRC, kann jetzt nicht prüfen) eine gute alte Druckanweisung verwenden, deren Ausgabe in der WB-Konsole erscheint. Persönlich habe ich selten einen Bedarf an Debugger für diesen Zweck (Debugging-Paket beim Laden)

BEARBEITEN 2

Als Antwort auf die Änderung in der Frage:

In Bezug auf die Reihenfolge der Definitionen: Ja, Sie können dies tun, und es löst dieses spezielle Problem. Aber im Allgemeinen ist das nicht robust, und ich würde es nicht als eine gute allgemeine Methode betrachten. Es ist schwer, einen konkreten Ratschlag für einen Fall zu geben, da es etwas außerhalb seines Kontexts liegt, aber mir scheint, dass die Verwendung von HoldPattern hier nicht gerechtfertigt ist. Wenn dies zur Fehlerbehandlung getan wird, gibt es andere Möglichkeiten ohne UpValues zu verwenden.

Im Allgemeinen wird UpValues am häufigsten verwendet, um eine Funktion auf sichere Weise zu überladen, ohne der Funktion überladene Regeln hinzuzufügen. Ein Ratschlag ist es, zu vermeiden, dass UpValues mit Köpfen verknüpft wird, die auch UpValues haben und auswerten können. Dadurch beginnen Sie, ein Spiel mit dem Bewerter zu spielen, und werden schließlich verlieren. Am sichersten ist es, DownValues an inerte Symbole (Köpfe, Container) anzuhängen, die oft einen "Typ" von Objekten darstellen, auf denen Sie eine bestimmte Funktion überladen möchten.

In Bezug auf meinen Kommentar zum Vorhandensein von UpValues , was auf ein schlechtes Design hindeutet. Es gibt sicherlich sind legitime Verwendungen für HoldPattern , wie diese (etwas künstliche):

%Vor%

Hier ist es gerechtfertigt, weil HoldPattern in vielen Fällen unbewertet bleibt und in seiner unbewerteten Form nützlich ist - da man folgern kann, dass es eine Summe darstellt. Wir brauchen Plus hier wegen der Art, wie HoldPattern für ein einzelnes Argument definiert ist, und weil ein Muster während der Definition ein einzelnes Argument ist (obwohl es im Allgemeinen mehrere Argumente beschreibt). Daher verwenden wir Plus hier, um zu verhindern, dass das Muster als normales Argument behandelt wird. Dies unterscheidet sich jedoch größtenteils von den beabsichtigten Anwendungsfällen für HoldPattern . Wann immer dies der Fall ist (wir sind sicher, dass die Definition für beabsichtigte Anwendungsfälle in Ordnung ist), ist Plus in Ordnung. Beachten Sie, dass dieses Beispiel auch fragil ist:

%Vor%

Der Grund, warum es immer noch in Ordnung ist, ist, dass wir normalerweise HoldPattern nicht für ein einzelnes Argument verwenden.

Aber es gibt eine zweite Gruppe von Fällen, bei denen die Struktur der normalerweise gelieferten Argumente der Struktur der für die Definition verwendeten Muster entspricht. In diesem Fall zeigt die Musterauswertung während der Zuweisung an, dass die gleiche Auswertung mit den tatsächlichen Argumenten während der Funktionsaufrufe erfolgt. Ihre Verwendung fällt in diese Kategorie. Mein Kommentar für einen Konstruktionsfehler war für solche Fälle - Sie können verhindern, dass das Muster bewertet wird, aber Sie müssen auch verhindern, dass die Argumente ausgewertet werden, damit dies funktioniert. Und Mustervergleiche gegen nicht vollständig ausgewertete Ausdrücke sind fragil.Außerdem sollte die Funktion niemals zusätzliche Bedingungen (außer dem, was sie eintippen kann) für die Argumente annehmen.

    
Leonid Shifrin 14.09.2011, 00:16
quelle