2 Stimmen

Korrektur der Combinatorica-Neudefinition von Element

Mein Code stützt sich auf die Version von Element die wie folgt funktioniert MemberQ , aber wenn ich lade Combinatorica , Element wird umdefiniert und funktioniert wie Part . Wie lässt sich dieser Konflikt am einfachsten beheben? Wie lautet insbesondere die Syntax zum Entfernen der Definition von Combinatorica aus DownValues ? Hier ist, was ich bekomme für DownValues[Element]

{HoldPattern[
   Combinatorica`Private`a_List \[Element] \
{Combinatorica`Private`index___}] :> 
  Combinatorica`Private`a[[Combinatorica`Private`index]], 
 HoldPattern[Private`x_ \[Element] Private`list_List] :> 
  MemberQ[Private`list, Private`x]}

4voto

WReach Punkte 17728

Wenn Ihr Ziel darin besteht, zu verhindern, dass Combinatorica die Definition überhaupt installiert, können Sie dies erreichen, indem Sie das Paket zum ersten Mal laden:

Block[{Element}, Needs["Combinatorica`"]]

Dies wird jedoch mit ziemlicher Sicherheit dazu führen, dass alle Combinatorica-Funktionen, die von der Definition abhängen, fehlschlagen (was für Ihre spezielle Anwendung von Bedeutung sein kann oder auch nicht).

3voto

Leonid Shifrin Punkte 22309

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.

1voto

Janus Punkte 5159

Zum Entfernen Combinatorica Definition, verwenden Sie Unset oder die entsprechende Form =. . Das Muster, das Sie aufheben können, finden Sie in der Information Ausgabe, die Sie in der Frage angeben:

Unprotect[Element];
Element[a_List, {index___}] =.
Protect[Element];

Die Sorge wäre natürlich, dass Combinatorica intern von dieser schlecht durchdachten Neudefinition abhängt, aber Sie haben Grund zu der Annahme, dass dies nicht der Fall ist, da die Information Ausgabe der neu definierten Element sagt:

Die Verwendung der Funktion Element in Combinatorica ist nun obsolet, obwohl der Funktionsaufruf Element[a, p] liefert immer noch das p-te Element der verschachtelten Liste a, wobei p eine Liste von Indizes ist.

HTH

1voto

qm2008q Punkte 11

Ich schlage einen ganz anderen Ansatz vor als das Entfernen von Element aus DownValues. Verwenden Sie einfach den vollständigen Namen der Funktion Element.

Wenn also das Original

System`Element[]

Die Standardeinstellung ist nun

Combinatorica`Element[]

wegen des Ladens des Combinatorica-Pakets.

Verwenden Sie einfach explizit

System`Element[]

wo immer Sie es brauchen. Überprüfen Sie natürlich, ob System der richtige Kontext ist, indem Sie die Funktion Context verwenden:

Context[Element]

Dieser Ansatz gewährleistet mehrere Dinge:

  1. Das Combinatorica-Paket funktioniert auch dann noch in Ihrem Notebook, wenn das Combinatorica-Paket in Zukunft aktualisiert wird
  2. Sie müssen die Funktion Element nicht neu definieren, wie einige vorgeschlagen haben
  3. Bei Bedarf können Sie die Funktion Combinatorica`Element verwenden

Der einzige Nachteil ist, dass man es jedes Mal explizit schreiben muss.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X