2011-01-15 5 views
2

내 코드는 MemberQ처럼 작동하는 Element 버전을 사용하지만 Combinatorica을로드하면 PartPart처럼 작동하도록 재정의됩니다. 이 충돌을 수정하는 가장 쉬운 방법은 무엇입니까? 구체적으로, Combinatorica의 정의를 DownValues에서 제거하는 구문은 무엇입니까? 여기 내가 DownValues[Element]요소의 Combinatorica 재정의 해결

{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]} 

답변

4

당신의 목표는 처음부터 정의를 설치하는 Combinatorica을 방지하는 경우, 당신은 이렇게 처음으로 패키지를로드하여이 결과를 얻을 수 있습니다 : 그러나

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

, 이것은 거의 확실하게 정의에 의존하는 Combinatorica 기능을 실패하게 만들 것입니다 (특정 응용 프로그램에서 우려 할 수도 있고 그렇지 않을 수도 있음).

+0

Combinatorica의 "Algorithmic Graph Theory"의 모든 기능은 요소가 없어도 정상적으로 작동하는 것으로 보입니다 –

+1

좋은 트릭 이죠. 확실히 그 용도가 있습니다.이 화신은 내 마음을 넘지 않았습니다. 개발자에게 큰 도움이 될 수 있습니다. 나쁜 점은 재사용 가능성을 심각하게 저해한다는 것입니다 (다른 사용자를 의미 함). 예를 들어, 코드를 사용하는 코드가 패키지에 포함되어 있고 사용자가 Combinatorica를 사용한다는 사실을 모르는 경우입니다. 따라서 사용자는 먼저이 파일을로드 한 다음 Combinatorica를로드합니다.이 파일은 다른 어떤 것도 필요합니다. Combinatorica는 이미 $ ContextPath에 있으므로 두 번째로로드되지 않으며 일부는 손상됩니다. 이러한 세부 사항을 모른 채로 이것은 수수께끼처럼 보입니다. –

+0

하지만 악의 근원은 내장 코드에 과부하가 걸린 패키지 코드에있는 것으로 보입니다. 필자는 이것이 실제로 여러 타사 패키지를 사용하는 대규모 프로젝트에서 매우 심각한 문제라고 생각합니다. 그러한 버그는 잡기가 매우 어려울 것입니다. 적어도 패키지 가져 오기 중 시스템 심볼의 재정의를 모니터링하고 충돌 가능성을보고하는 도구가 있어야합니다. Set과 SetDelayed를 오버로드하면이 작업을 수행 할 수 있지만, 특히로드 타임뿐만 아니라 런타임에도 정의를 작성할 수 있기 때문에 기본 제공 기능을 지원하는 것이 좋습니다. –

3

당신은 몇 가지 작업을 수행 할 수 있습니다. 당신은 문맥에 따라 정의를 삭제하려면, 당신이 뭔가를 할 수

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의 함수가 오버로드 된 요소에 의존)에서 가져올 수 있습니다. 이것은 큰 문제가 아니며 단지 돌보는 것이 필요합니다.

결론은 다음과 같습니다. 가능한 경우 내장 기능의 오버로드를 피하십시오. 이 경우에는이 정의에 직면하게됩니다. 그러나이 문제에 직면 한 사람이 패키지를 사용하는 사람 (몇 개월 후인 경우), 다른 사람과 패키지를 결합하려는 사람 너와 같은 시스템 기능에 과부하가 일어난다. 물론, 그것은 또한 패키지의 사용자가 누구인지에 달려 있습니다. 자신이나 잠재적으로 다른 사용자뿐입니다. 그러나 디자인 측면에서, 그리고 장기적으로 볼 때 처음부터 후자의 시나리오를 가정하면 더 나을 것입니다.

+0

블록이 방해가 될 수는 없지만 "요소"의이 사용자 지정 버전을 사용하는 패키지가 있습니다 ... 그래서 블록 안의 해당 패키지에서 함수 호출을 모두 래핑해야합니다. –

+0

당신이해야 할 일은 다른 것들을 사용하는 가장 높은 레벨의 함수를 감싸는 것입니다 (당신이 가지고 있다고 가정합니다, 그러나 이것이 일반적인 관행입니다). 일반적으로 너무 적은 함수로 구성된 몇 가지 최소 인터페이스를 추출 할 수 있습니다. 자동으로 메타 프로그래밍을 사용하여 내 게시물의 업데이트를 볼 수도 있습니다. 저는 실제로 이런 종류의 일을합니다 : Mathematica 동적 메타 프로그래밍 기능은 다른 많은 언어들보다 훨씬 강력합니다. 사람들이 더 자주 사용하지 않는 이유를 알지 못합니다 (문화적인 것입니까?) –

1

Combinatorica의 정의를 제거하려면 Unset 또는 해당하는 양식 =.을 사용하십시오. 패턴은 당신이 질문에 보여 Information 출력에서 ​​잡을 수있는 설정 해제하기 : Combinatorica이 잘못 생각 재정에 내부적으로 의존,

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

는 걱정은 물론 것,하지만 당신은 믿을 이유가 되지하려면 경우가 재정의 Element에서 Information 출력 말한다 같이 함수 호출 요소 [A, P]가 여전히 PTH를 제공하지만

함수 Combinatorica에 소자의 사용은 이제 쓸모 중첩 목록 a의 요소. 여기서 p는 색인 목록입니다.

HTH

1

나는 DownValues에서 요소를 제거하는 것과는 완전히 다른 접근 방식을 제안합니다. Element 함수의 전체 이름을 사용하기 만하면됩니다.

그래서 원래는

System`Element[] 

기본 이제 때문에 Combinatorica 패키지를로드의

Combinatorica`Element[] 

입니다 경우. 당신이 그것을 필요로 할 때마다

그냥 명시 적으로

System`Element[] 

사용합니다.물론 시스템 컨텍스트 기능을 사용하여 올바른 컨텍스트인지 확인 :

Context[Element] 

이 방법은 몇 가지를 보장 :

  1. Combinatorica 패키지는 여전히 Combinatorica 패키지가 업데이트 될 경우에도 노트북에서 작동 필요한 경우 일부는
  2. 당신은 Combinatorica`Element 기능을 사용할 수 있습니다 제안으로 미래
  3. 에 당신은 습관, 요소의 기능을 재정의해야

유일한 단점은 매번 명시 적으로 작성해야한다는 것입니다.

+3

질문의 요점을 놓친 것 같습니다. 섀도 잉 문제가있을 때 좋습니다 (콘텍스트 이름을 하드 코딩하면 유지 관리 기능이 손상 될 수 있지만 "시스템"은 괜찮습니다). 그러나 여기서 "Combinatorica"는''System'Element ''를 수정하는 것이 었으며, OP의 맞춤 코드가 수행 한 것입니다. 따라서 문제는 동일한 기호에 대한 충돌하는 정의의 수준에 있으며 충돌하는 기호에는 해당하지 않습니다. –