Om man bortser från WB (som egentligen inte behövs för att svara på din fråga) - så verkar problemet ha ett enkelt svar baserat enbart på hur uttryck utvärderas under uppdrag. Här är ett exempel:
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
För att få det att fungera gjorde jag medvetet en definition för notGoodQ
för att alltid returnera True
. Varför var g[x0_]
utvärderas under uppdraget genom TagSetDelayed
? Svaret är att medan TagSetDelayed
(samt SetDelayed
) i en uppgift h/:f[h[elem1,...,elemn]]:=...
tillämpar inga regler som f
kan ha, kommer den att utvärdera h[elem1,...,elem2]
, samt f
. Här är ett exempel:
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
Det faktum att TagSetDelayed
är HoldAll
betyder inte att den inte utvärderar sina argument - det betyder bara att argumenten kommer till den outvärderade, och om de kommer att utvärderas eller inte beror på semantiken för TagSetDelayed
(som jag kort beskrev ovan). Detsamma gäller för SetDelayed
, så det vanliga påståendet att det "inte utvärderar sina argument" är inte bokstavligen korrekt. Ett mer korrekt påstående är att den tar emot argumenten outvärderade och utvärderar dem på ett speciellt sätt - inte utvärdera r.h.s, medan för l.h.s. utvärdera huvud och element men inte tillämpa regler för huvudet. För att undvika det kan du slå in saker i HoldPattern
, så här:
Clear[g,notGoodQ];
notGoodQ[x_]:=EvenQ[x];
g[x_?notGoodQ]:=(Message[g::nogood,x];Abort[])
g/:cccQ[HoldPattern[g[x0_]]]:=True;
Detta går igenom. Här är lite användning:
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
Observera dock att behovet av HoldPattern
inuti din vänstra sida när du gör en definition är ofta ett tecken på att uttrycket inuti ditt huvud också kan utvärderas under funktionsanropet, vilket kan bryta din kod. Här är ett exempel på vad jag menar:
In[1532]:=
ClearAll[f,h];
f[x_]:=x^2;
f/:h[HoldPattern[f[y_]]]:=y^4;
Den här koden försöker fånga fall som h[f[something]]
, men det kommer uppenbarligen att misslyckas eftersom f[something]
kommer att utvärdera innan utvärderingen kommer till h
:
In[1535]:= h[f[5]]
Out[1535]= h[25]
För mig är behovet av HoldPattern
på l.h.s. är ett tecken på att jag måste ompröva min design.
REDIGERA
Angående felsökning under laddning i WB, en sak du kan göra (IIRC, kan inte kontrollera just nu) är att använda gamla gamla utskriftssatser, vars utdata kommer att visas i WB:s konsol. Personligen känner jag sällan ett behov av debugger för detta ändamål (felsökningspaket vid laddning)
REDIGERA 2
Som svar på redigeringen i frågan:
Angående definitionsordningen:ja, du kan göra detta, och det löser just detta problem. Men generellt sett är detta inte robust, och jag skulle inte anse det som en bra allmän metod. Det är svårt att ge ett bestämt råd för ett aktuellt fall, eftersom det är lite utanför sitt sammanhang, men det verkar som om användningen av UpValues
här är obefogat. Om detta görs för felhantering, finns det andra sätt
för att göra det utan att använda UpValues
.
I allmänhet UpValues
används oftast för att överbelasta någon funktion på ett säkert sätt, utan att lägga till någon regel för funktionen som överbelastas. Ett råd är att undvika att associera UpValues
med huvuden som också har DownValues
och kan utvärdera -genom att göra detta börjar du spela ett spel med evaluator och kommer så småningom att förlora. Det säkraste är att bifoga UpValues
att inerta symboler (huvuden, behållare), som ofta representerar en "typ" av objekt på vilka du vill överbelasta en given funktion.
Angående min kommentar om förekomsten av HoldPattern
indikerar en dålig design. Det finns verkligen legitima användningar av HoldPattern
, som den här (något konstgjorda):
In[25]:=
Clear[ff,a,b,c];
ff[HoldPattern[Plus[x__]]]:={x};
ff[a+b+c]
Out[27]= {a,b,c}
Här är det motiverat eftersom i många fall Plus
förblir outvärderad och är användbar i sin outvärderade form - eftersom man kan dra slutsatsen att den representerar en summa. Vi behöver HoldPattern
här på grund av sättet Plus
definieras på ett enda argument, och eftersom ett mönster råkar vara ett enda argument (även om det generellt beskriver flera argument) under definitionen. Så vi använder HoldPattern
här för att förhindra att mönstret behandlas som normalt argument, men detta skiljer sig mest från de avsedda användningsfallen för Plus
. När så är fallet (vi är säkra på att definitionen kommer att fungera bra för avsedda användningsfall), HoldPattern
är bra. Notera b.t.w. att detta exempel också är bräckligt:
In[28]:= ff[Plus[a]]
Out[28]= ff[a]
Anledningen till att det fortfarande mestadels är OK är att vi normalt sett inte använder Plus
på ett enda argument.
Men det finns en andra grupp av fall, där strukturen av vanligtvis tillhandahållna argument är densamma som strukturen för mönster som används för definitionen. I det här fallet indikerar mönsterutvärdering under uppdraget att samma utvärdering kommer att ske med faktiska argument under funktionsanropen. Din användning faller inom denna kategori. Min kommentar för ett designfel var för sådana fall - du kan förhindra att mönstret utvärderas, men du måste förhindra att argumenten också utvärderas för att få detta att fungera. Och mönstermatchning mot inte helt utvärderade uttryck är bräckligt. Funktionen bör heller aldrig anta några extra villkor (utöver vad den kan typkontrollera) för argumenten.