Исправление Combinatorica переопределения элемента - PullRequest
2 голосов
/ 16 января 2011

Мой код использует версию Element, которая работает как MemberQ, но когда я загружаю Combinatorica, Element переопределяется, чтобы работать как Part.Какой самый простой способ исправить этот конфликт?В частности, каков синтаксис для удаления определения Combinatorica из DownValues?Вот что я получу за 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]}

Ответы [ 4 ]

4 голосов
/ 18 января 2011

Если ваша цель состоит в том, чтобы в первую очередь не дать Combinatorica установить определение, вы можете достичь этого результата, загрузив пакет в первый раз, таким образом:

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

Однако это почти наверняка приведет к сбоям любых функций Combinatorica, которые зависят от определения (которые могут или не могут иметь значение в вашем конкретном приложении).

3 голосов
/ 16 января 2011

Вы можете сделать несколько вещей. Введем удобную функцию

ClearAll[redef];
SetAttributes[redef, HoldRest];
redef[f_, code_] := (Unprotect[f]; code; Protect[f])

Если вы уверены в порядке определений, вы можете сделать что-то вроде

redef[Element, DownValues[Element] = Rest[DownValues[Element]]]

Если вы хотите удалить определения, основанные на контексте, вы можете сделать что-то вроде этого:

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

Edit:

Если вам нужно автоматизировать использование Block, вот пример пакета, показывающий один из способов, как это можно сделать:

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[]

Вы можете загрузить пакет и посмотреть значения DownValues ​​для f1 и f2, например:

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

Та же схема будет работать и для функций, не входящих в тот же пакет. На самом деле, вы могли бы отделить нижняя часть (пакет обработки кода) должна быть пакетом сама по себе, импортировать ее в любой другой пакет, в который вы хотите добавить Block в определения ваших функций, а затем просто вызвать что-то вроде postprocessDefs[mainContext], как указано выше. Вы можете сделать функцию, которая делает определения внутри блока (elementDef здесь), дополнительным параметром для обобщенной версии elemExec, что сделает этот подход более модульным и многократно используемым.

Если вы хотите более избирательно относиться к функциям, в которые вы хотите ввести блокировку, это также можно сделать различными способами. Фактически, тогда вся схема внедрения блоков может быть более чистой, но при реализации каждой функции потребуется немного больше внимания, в то время как описанный выше подход является полностью автоматическим. При необходимости я могу опубликовать код, который проиллюстрирует это.

Еще одна вещь: за менее навязчивую природу этого метода вы платите цену - динамический контекст (блок) обычно сложнее контролировать, чем конструкции с лексической областью. Таким образом, вы должны точно знать, какие части стека оценки вы хотите применить. Например, я бы не хотел вставлять Блок в определение функции более высокого порядка, которая принимает некоторые функции в качестве параметров, поскольку эти функции могут происходить из кода, который принимает другие определения (как, например, функции Combinatorica, основанные на перегруженном элементе). Это не большая проблема, просто требует ухода.

Суть в следующем: кажется, старайтесь избегать перегрузки встроенных модулей, если это вообще возможно. В этом случае вы столкнулись с этим определением столкновения самих себя, но было бы еще хуже, если бы тот, кто сталкивается с этой проблемой, был пользователем вашего пакета (может быть, вы сами через несколько месяцев), который хочет объединить ваш пакет с другим (который происходит перегрузка тех же системных функций, что и у вас). Конечно, это также зависит от того, кто будет пользователями вашего пакета - только вы или потенциально другие. Но с точки зрения дизайна и в долгосрочной перспективе вам, возможно, будет лучше принять последний сценарий с самого начала.

1 голос
/ 05 сентября 2011

Я предлагаю совершенно иной подход, чем удаление Элемента из DownValues. Просто используйте полное имя функции Элемент.

Итак, если оригинал

System`Element[]

по умолчанию сейчас

Combinatorica`Element[]

из-за загрузки пакета Combinatorica.

Просто явно используйте

System`Element[]

везде, где вам это нужно. Конечно, проверьте, что система является правильным контекстом, используя функцию контекста:

Context[Element]

Этот подход обеспечивает несколько вещей:

  1. Пакет Combinatorica будет по-прежнему работать в вашем ноутбуке, даже если в будущем будет обновлен пакет Combinatorica
  2. Вам не нужно переопределять функцию Element, как некоторые предлагали
  3. При необходимости вы можете использовать функцию Combinatorica`Element

Единственным недостатком является необходимость каждый раз явно писать это.

1 голос
/ 17 января 2011

Чтобы удалить определение Combinatorica, используйте Unset или эквивалентную форму =..Шаблон для сброса вы можете получить из вывода Information, который вы показываете в вопросе:

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

Разумеется, беспокоит то, что Combinatorica внутренне зависит от этого непродуманного переопределения, ноу вас есть основания полагать, что это не так, поскольку вывод Information из переопределенного Element говорит:

Использование функции Element в Combinatorica теперь устарело, хотя вызов функцииЭлемент [a, p] по-прежнему дает p-й элемент вложенного списка a, где p - список индексов.

HTH

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...