당신은 몇 가지 작업을 수행 할 수 있습니다. 당신은 문맥에 따라 정의를 삭제하려면, 당신이 뭔가를 할 수
redef[Element, DownValues[Element] = Rest[DownValues[Element]]]
처럼 뭔가를 할 수 있습니다, 당신은 정의의 순서에 대한 확신한다면 우리가 편리한 함수
ClearAll[redef];
SetAttributes[redef, HoldRest];
redef[f_, code_] := (Unprotect[f]; code; Protect[f])
을 소개하자
를 : -이 같은 정의의 순서를 변경하기보다는 삭제
는
redef[Element, DownValues[Element] =
DeleteCases[DownValues[Element],
rule_ /; Cases[rule, x_Symbol /; (StringSplit[Context[x], "`"][[1]] ===
"Combinatorica"), Infinity, Heads -> True] =!= {}]]
또한 부드러운 방법을 사용할 수 있습니다
redef[Element, DownValues[Element] = RotateRight[DownValues[Element]]]
이 문제를 처리하는 데는 여러 가지 다른 방법이 있습니다. 또 다른 하나는 (내가 이미 권장 한) 이것이 적합한 경우 UpValues를 사용하는 것입니다. 마지막으로 여기서 언급하고 싶은 것은 Block을 기반으로 한 일종의 맞춤 동적 범위 지정 구문을 만들어 코드 주위에 포장하는 것입니다. 개인적으로 가장 엄격한 정의가 적용되기를 원한다면 적용 할 수있는 가장 안전한 변형입니다 (다양한 정의가 작성 될 수있는 순서는 중요하지 않으므로 모든 정의가 제거되어 사용자 정의를 추가 할 수 있기 때문에). 또한 정의를 적용 할 장소 (평가 스택의 일부를 의미하는 "장소"로) 이외의 다른 정의도 계속 적용되므로이 방법이 가장 방해가되지 않는 방법으로 생각됩니다. 여기가 보일 수 있습니다 어떻게 사용의
elementDef[] := Element[x_, list_List] := MemberQ[list, x];
ClearAll[elemExec];
SetAttributes[elemExec, HoldAll];
elemExec[code_] := Block[{Element}, elementDef[]; code];
예 :
In[10]:= elemExec[Element[1,{1,2,3}]]
Out[10]= True
편집 :
당신이 블록의 사용을 자동화해야하는 경우, 여기에 한 가지 방법을 보여주는 예제 패키지입니다 어떻게 할 수 있습니까?
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[]
패키지를로드하고 ex1 le :
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]]}
동일한 구성표가 동일한 패키지에없는 기능에도 작동합니다. 실제로 하단 부분 (코드 처리 패키지)을 패키지로 분리하여 패키지를 함수 정의에 삽입하려는 다른 패키지로 가져온 다음 postprocessDefs[mainContext]
과 같은 코드를 호출 할 수 있습니다 , 위와 같이. 블록 (elementDef
여기) 내의 정의를 elemExec
의 일반화 된 버전에 대한 추가 매개 변수로 만드는 함수를 만들면이 방법을 모듈화하고 재사용 할 수 있습니다.
차단을 주입 할 기능에 대해 더 자세히 선택하고 싶다면 다양한 방법으로 수행 할 수 있습니다. 실제로, 전체 Block-injection 체계는 더 깨끗해질 수 있지만, 위의 접근법은 완전히 자동이지만 각 함수를 구현할 때는 약간 더주의를 요할 것입니다.필자는 필요한 경우이를 설명하는 코드를 게시 할 수 있습니다.
한 가지 더 :이 방법의 방해가 적기 때문에 가격을 지불해야합니다. 동적 범위 (블록)는 어휘 적 범위 구조보다 제어하기가 일반적으로 어렵습니다. 따라서 평가 스택의 해당 부분을 정확하게 알고 있어야합니다. 예를 들어, 일부 함수를 매개 변수로 사용하는 상위 함수의 정의에 Block을 삽입하는 것을 주저합니다. 이러한 함수는 다른 정의를 가정하는 코드 (예 : Combinatorica의 함수가 오버로드 된 요소에 의존)에서 가져올 수 있습니다. 이것은 큰 문제가 아니며 단지 돌보는 것이 필요합니다.
결론은 다음과 같습니다. 가능한 경우 내장 기능의 오버로드를 피하십시오. 이 경우에는이 정의에 직면하게됩니다. 그러나이 문제에 직면 한 사람이 패키지를 사용하는 사람 (몇 개월 후인 경우), 다른 사람과 패키지를 결합하려는 사람 너와 같은 시스템 기능에 과부하가 일어난다. 물론, 그것은 또한 패키지의 사용자가 누구인지에 달려 있습니다. 자신이나 잠재적으로 다른 사용자뿐입니다. 그러나 디자인 측면에서, 그리고 장기적으로 볼 때 처음부터 후자의 시나리오를 가정하면 더 나을 것입니다.
Combinatorica의 "Algorithmic Graph Theory"의 모든 기능은 요소가 없어도 정상적으로 작동하는 것으로 보입니다 –
좋은 트릭 이죠. 확실히 그 용도가 있습니다.이 화신은 내 마음을 넘지 않았습니다. 개발자에게 큰 도움이 될 수 있습니다. 나쁜 점은 재사용 가능성을 심각하게 저해한다는 것입니다 (다른 사용자를 의미 함). 예를 들어, 코드를 사용하는 코드가 패키지에 포함되어 있고 사용자가 Combinatorica를 사용한다는 사실을 모르는 경우입니다. 따라서 사용자는 먼저이 파일을로드 한 다음 Combinatorica를로드합니다.이 파일은 다른 어떤 것도 필요합니다. Combinatorica는 이미 $ ContextPath에 있으므로 두 번째로로드되지 않으며 일부는 손상됩니다. 이러한 세부 사항을 모른 채로 이것은 수수께끼처럼 보입니다. –
하지만 악의 근원은 내장 코드에 과부하가 걸린 패키지 코드에있는 것으로 보입니다. 필자는 이것이 실제로 여러 타사 패키지를 사용하는 대규모 프로젝트에서 매우 심각한 문제라고 생각합니다. 그러한 버그는 잡기가 매우 어려울 것입니다. 적어도 패키지 가져 오기 중 시스템 심볼의 재정의를 모니터링하고 충돌 가능성을보고하는 도구가 있어야합니다. Set과 SetDelayed를 오버로드하면이 작업을 수행 할 수 있지만, 특히로드 타임뿐만 아니라 런타임에도 정의를 작성할 수 있기 때문에 기본 제공 기능을 지원하는 것이 좋습니다. –