Использование `With` со списком` Rules` - но без влияния на нормальное поведение `With` - PullRequest
6 голосов
/ 04 марта 2011

Скажем, у меня есть список Rules

rules = {a -> b, c -> d};

, который я использую в ноутбуке.Затем в какой-то момент имеет смысл захотеть применить правила до того, как в выражении произойдут любые другие оценки.Обычно, если вы хотите что-то подобное, вы можете использовать

In[2]:= With[{a=b,c=d}, expr[a,b,c,d]]
Out[2]= expr[b, b, d, d]

Как мне взять rules и вставить его в первый аргумент With?


Редактировать

Оба Некоторые решения терпят неудачу, делают все, что я искал - но я должен был подчеркнуть этот момент немного больше.См. Жирную часть выше.

Например, давайте посмотрим на

rules = {a -> {1, 2}, c -> 1};

Если я использую эти пароли в With, я получу

In[10]:= With[{a={1,2},c=1}, Head/@{a,c}]
Out[10]= {List,Integer}

Некоторые версиииз WithRules yield

In[11]:= WithRules[rules, Head/@{a,c}]
Out[11]= {Symbol, Symbol}

( На самом деле , я не заметил, что у ответа Эндрю был атрибут HoldRest - поэтому он работает так, как я хотел.)

Ответы [ 3 ]

11 голосов
/ 04 марта 2011

Вы хотите использовать Удерживать , чтобы создать свое утверждение With.Вот один из способов;может быть проще:

In[1]:= SetAttributes[WithRules, HoldRest]

In[2]:= WithRules[rules_, expr_] := 
 With @@ Append[Apply[Set, Hold@rules, {2}], Unevaluated[expr]]

Проверьте это:

In[3]:= f[args___] := Print[{args}]

In[4]:= rules = {a -> b, c -> d};

In[5]:= WithRules[rules, f[a, c]]

During evaluation of In[5]:= {b,d}

(я использовал Print, чтобы любая ошибка, связанная с моей случайной оценкой expr слишком рано, была очевидной.)

2 голосов
/ 04 марта 2011

Я давно использую следующую форму WithRules. По сравнению с тем, что написал Эндрю Мойлан, он связывается последовательно, так что вы можете сказать, например, WithRules[{a->b+1, b->2},expr] и получите a, расширенный до 3:

SetAttributes[WithRules, HoldRest]
WithRules[rules_, expr_] := ReleaseHold@Module[{notSet}, Quiet[
     With[{args = Reverse[rules /. Rule[a_, b_] -> notSet[a, b]]},
       Fold[With[{#2}, #1] &, Hold@expr, args]] /. notSet -> Set, 
   With::lvw]]

Это также было опубликовано как ответ на несвязанный вопрос , и, как отмечалось там, он обсуждался (по крайней мере) пару раз в usenet:

НТН

EDIT : добавлена ​​пара ReleaseHold, Hold, чтобы expr оставалась без оценки до тех пор, пока не будут применены правила.

1 голос
/ 04 марта 2011

Одна проблема с решением Эндрю состоит в том, что он отображает проблему обратно на С, и это не принимает подписанные переменные.Таким образом, следующее генерирует сообщения.

WithRules[{Subscript[x, 1] -> 2, Subscript[x, 2] -> 3}, 
 Power[Subscript[x, 1], Subscript[x, 2]]]

Учитывая, что With выполняет синтаксическую замену своего тела, мы можем альтернативно установить WithRules следующим образом:

ClearAll[WithRules]; SetAttributes[WithRules, HoldRest];
WithRules[r : {(_Rule | _RuleDelayed) ..}, body_] := 
 ReleaseHold[Hold[body] /. r]

Тогда

In[113]:= WithRules[{Subscript[x, 1] -> 2, 
  Subscript[x, 2] -> 3}, Subscript[x, 1]^Subscript[x, 2]]

Out[113]= 8

Редактировать : Для решения действительных проблем, поднятых Леонидом, следующая версия будет безопасна:

ClearAll[WithRules3]; SetAttributes[WithRules3, HoldRest];
WithRules3[r : {(_Rule | _RuleDelayed) ..}, body_] := 
 Developer`ReplaceAllUnheld[Unevaluated[body], r]

Тогда

In[194]:= WithRules3[{Subscript[x, 1] -> 2, Subscript[x, 2] -> 3}, 
 Subscript[x, 1]^Subscript[x, 2]]

Out[194]= 8

In[195]:= WithRules3[{x -> y}, f[y_] :> Function[x, x + y]]

Out[195]= f[y_] :> Function[x, x + y]

Редактировать 2 : Даже WithRules3не полностью эквивалентен версии Эндрю:

In[206]:= WithRules3[{z -> 2}, f[y_] :> Function[x, x + y + z]]

Out[206]= f[y_] :> Function[x, x + y + z]

In[207]:= WithRules[{z -> 2}, f[y_] :> Function[x, x + y + z]]

Out[207]= f[y$_] :> Function[x$, x$ + y$ + 2]
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...