Sie können mehrere Dinge tun. Wir wollen eine Komfortfunktion einführen
ClearAll[redef];
SetAttributes[redef, HoldRest];
redef[f_, code_] := (Unprotect[f]; code; Protect[f])
Wenn Sie sich über die Reihenfolge der Definitionen im Klaren sind, können Sie etwa so vorgehen
redef[Element, DownValues[Element] = Rest[DownValues[Element]]]
Wenn Sie Definitionen auf der Grundlage des Kontexts löschen möchten, können Sie wie folgt vorgehen:
redef[Element, DownValues[Element] =
DeleteCases[DownValues[Element],
rule_ /; Cases[rule, x_Symbol /; (StringSplit[Context[x], "`"][[1]] ===
"Combinatorica"), Infinity, Heads -> True] =!= {}]]
Sie können auch einen sanfteren Weg wählen - Definitionen neu anordnen statt löschen:
redef[Element, DownValues[Element] = RotateRight[DownValues[Element]]]
Es gibt viele andere Möglichkeiten, mit diesem Problem umzugehen. Eine andere (die ich bereits empfohlen habe) ist die Verwendung von UpValues, wenn diese geeignet ist. Die letzte Möglichkeit, die ich hier erwähnen möchte, besteht darin, eine Art benutzerdefiniertes dynamisches Scoping-Konstrukt auf der Grundlage von Block zu erstellen und es um Ihren Code zu wickeln. Ich persönlich halte dies für die sicherste Variante, wenn Sie wollen, dass ausschließlich Ihre Definition gilt (weil es sich nicht um die Reihenfolge kümmert, in der verschiedene Definitionen erstellt worden sein könnten - es entfernt sie alle und fügt nur Ihre hinzu). Sie ist auch insofern sicherer, als dass außerhalb der Stellen, an denen Ihre Definitionen gelten sollen (mit "Stellen" meine ich Teile des Auswertungsstapels), immer noch andere Definitionen gelten, so dass dies die am wenigsten aufdringliche Methode zu sein scheint. So könnte es aussehen:
elementDef[] := Element[x_, list_List] := MemberQ[list, x];
ClearAll[elemExec];
SetAttributes[elemExec, HoldAll];
elemExec[code_] := Block[{Element}, elementDef[]; code];
Beispiel für die Verwendung:
In[10]:= elemExec[Element[1,{1,2,3}]]
Out[10]= True
Edit :
Wenn Sie die Verwendung von Block automatisieren möchten, finden Sie hier ein Beispielpaket, das eine Möglichkeit aufzeigt, wie dies geschehen kann:
BeginPackage["Test`"]
var;
f1;
f2;
Begin["`Private`"];
(* Implementations of your functions *)
var = 1;
f1[x_, y_List] := If[Element[x, y], x^2];
f2[x_, y_List] := If[Element[x, y], x^3];
elementDef[] := Element[x_, list_List] := MemberQ[list, x];
(* The following part of the package is defined at the start and you don't
touch it any more, when adding new functions to the package *)
mainContext = StringReplace[Context[], x__ ~~ "Private`" :> x];
SetAttributes[elemExec, HoldAll];
elemExec[code_] := Block[{Element}, elementDef[]; code];
postprocessDefs[context_String] :=
Map[
ToExpression[#, StandardForm,
Function[sym,DownValues[sym] =
DownValues[sym] /.
Verbatim[RuleDelayed][lhs_,rhs_] :> (lhs :> elemExec[rhs])]] &,
Select[Names[context <> "*"], ToExpression[#, StandardForm, DownValues] =!= {} &]];
postprocessDefs[mainContext];
End[]
EndPackage[]
Sie können das Paket laden und sich z. B. die DownValues für f1 und f2 ansehen:
In[17]:= DownValues[f1]
Out[17]= {HoldPattern[f1[Test`Private`x_,Test`Private`y_List]]:>
Test`Private`elemExec[If[Test`Private`x\[Element]Test`Private`y,Test`Private`x^2]]}
Das gleiche Schema gilt auch für Funktionen, die nicht im gleichen Paket enthalten sind. Tatsächlich könnten Sie den den unteren Teil (Codeverarbeitungspaket) als eigenes Paket abtrennen, es in jedes andere Paket importieren Paket importieren, in dem Sie Block in die Definitionen Ihrer Funktionen einfügen wollen, und dann einfach etwas aufrufen wie postprocessDefs[mainContext]
wie oben. Sie könnten die Funktion, die die Definitionen innerhalb von Block ( elementDef
hier) zu einem zusätzlichen Parameter für eine verallgemeinerte Version von elemExec
was diesen Ansatz modularer und wiederverwendbar machen würde.
Wenn Sie bei der Auswahl der Funktionen, in die Sie Block einfügen möchten, selektiver vorgehen möchten, können Sie dies ebenfalls auf verschiedene Weise tun. In der Tat kann das gesamte Block-Injektionsschema dann sauberer gestaltet werden, aber es erfordert etwas mehr Sorgfalt bei der Implementierung jeder Funktion, während der obige Ansatz völlig automatisch ist. Ich kann den Code, der dies veranschaulicht, bei Bedarf zur Verfügung stellen.
Und noch etwas: Für die weniger aufdringliche Art dieser Methode zahlen Sie einen Preis - der dynamische Bereich (Block) ist in der Regel schwieriger zu kontrollieren als lexikalisch begrenzte Konstrukte. Sie müssen also genau wissen, auf welche Teile des Auswertungsstapels Sie dies anwenden wollen. Ich würde z.B. zögern, Block in eine Definition einer Funktion höherer Ordnung zu injizieren, die einige Funktionen als Parameter annimmt, da diese Funktionen aus Code stammen können, der andere Definitionen voraussetzt (wie z.B. Combinatorica-Funktionen, die sich auf überladene Elemente stützen). Dies ist kein großes Problem, erfordert aber Vorsicht.
Die Quintessenz daraus scheint zu sein: Versuchen Sie, eine Überlastung der eingebauten Komponenten zu vermeiden, wenn dies möglich ist. In diesem Fall sind Sie selbst mit diesem Definitionskonflikt konfrontiert, aber es wäre noch schlimmer, wenn derjenige, der mit diesem Problem konfrontiert ist, ein Benutzer Ihres Pakets ist (vielleicht Sie selbst ein paar Monate später), der Ihr Paket mit einem anderen kombinieren will (das zufällig dieselben Systemfunktionen wie das Ihre überlädt). Natürlich hängt es auch davon ab, wer die Nutzer Ihres Pakets sein werden - nur Sie selbst oder möglicherweise auch andere. Aber in Bezug auf das Design und auf lange Sicht ist es vielleicht besser, wenn Sie von Anfang an von letzterem Szenario ausgehen.