Подтвердить что ты не робот

Предотвращение оценки выражений Mathematica

В недавнем SO-вопросе было представлено три разных ответа, каждый из которых использовал другой метод предотвращения оценки выражения Equal[]. Они были

  • Defer[]
  • Unevaluated[]
  • HoldForm[]

Иногда мне все еще сложно выбирать между этими параметрами (и, судя по ответам на перед упомянутым вопросом, выбор не всегда ясен и для других людей). Может ли кто-нибудь написать четкое изложение об использовании этих трех методов?


Есть три других обертки  Hold[]  HoldPattern[]  HoldComplete[], и различные функции Attributes для функций   HoldAll, HoldFirst, HoldRest и числовые версии NHold*, которые также могут быть обсуждены, если хотите!

Изменить

Я только заметил, что это в основном повторение старого вопроса (который я уже сохранил, только что забыл...). Принятый ответ, связанный с этот разговор на конференции разработчиков Mathematica 1999 года, которая не обсуждает Defer, так как это "Новое в 6", Defer более тесно связан с интерфейсом, чем другие механизмы управления оценкой. Он используется для создания неоцененного вывода, который будет оцениваться, если он указан в выражении Input. Чтобы процитировать Центр документации:

Defer [expr] возвращает объект, который остается неизменным до тех пор, пока явно предоставлен как Mathematica ввода и Shift + Enter, Evaluate in Place и т.д.

4b9b3361

Ответ 1

Не касаясь Defer, так как я не очень много работал с ним и считаю, что в любом случае его поведение может быть воспроизведено другими упомянутыми обертками и обсуждать Hold вместо этого на HoldForm (разница действительно в как они печатаются), здесь - это ссылка на сообщение mathgroup, где я дал довольно подробное объяснение различий между Hold и Unevaluated, включая различия в использовании и в процессе оценки (в частности, мои вторая и третья должности).

Короче говоря, Hold используется для сохранения выражения, не оцененного между несколькими оценками (для неопределенного времени, пока оно нам не понадобится), является видимой оболочкой в ​​том смысле, что Depth[Hold[{1,2,3}]] не является то же самое, что и Depth[{1,2,3}] (это, конечно, следствие оценки), и обычно ничего особенного - просто обертка с атрибутом HoldAll, как и любая другая, кроме как "официальная" обертка для холдинга и которая лучше интегрируется с остальными системы, поскольку многие системные функции используют или ожидают его.

OTOH, Unevaluated[expr] используется временно, только один раз, компенсирует отсутствующий атрибут Hold * для функции, содержащей выражение expr. Хотя это приводит к поведению, которое потребовало бы, чтобы эта закрывающая функция удерживала expr, как если бы она имела атрибут Hold* -, Unevaluated принадлежит аргументу и работает только один раз для одной оценки, поскольку она лишается процесса, Кроме того, поскольку он становится разделенным, он часто невидим для окружающих оберток, в отличие от Hold. Наконец, это один из немногих "волшебных символов", наряду с Sequence и Evaluate - они глубоко подключены к системе и не могут быть легко реплицированы или заблокированы, в отличие от Hold - в этом смысле Unevaluated является более фундаментальным.

HoldComplete используется, когда требуется предотвратить определенные этапы процесса оценки, которые Hold не предотвращает. Это включает в себя последовательности сращивания, например:

In[25]:= {Hold[Sequence[1, 2]], HoldComplete[Sequence[1, 2]]}

Out[25]= {Hold[1, 2], HoldComplete[Sequence[1, 2]]},

найдите UpValues, например

In[26]:= 
ClearAll[f];
f /: Hold[f[x_]] := f[x];
f[x_] := x^2;

In[29]:= {Hold[f[5]], HoldComplete[f[5]]},

Out[29]= {25, HoldComplete[f[5]]}

и иммунитет к Evaluate:

In[33]:= 
ClearAll[f];
f[x_] := x^2;

In[35]:= {Hold[Evaluate[f[5]]], HoldComplete[Evaluate[f[5]]]}

Out[35]= {Hold[25], HoldComplete[Evaluate[f[5]]]}   

Другими словами, он используется, когда вы хотите предотвратить любую оценку выражения внутри, вообще. Как Hold, HoldComplete не имеет ничего особенного в том смысле, что это всего лишь "официальная" оболочка с атрибутом HoldAllComplete, и вы можете сделать свой собственный, который будет вести себя аналогичным образом.

Наконец, HoldPattern является обычной (обычной) головой с атрибутом HoldAll для целей оценки, но ее магия проявляется в сопоставлении с образцом: она невидима для шаблона-сопоставления и является очень важным компонентом языка, поскольку он позволяет согласовать шаблон с процессом оценки. Всякий раз, когда существует опасность того, что шаблон в некотором правиле может оцениваться, HoldPattern можно использовать, чтобы гарантировать, что этого не произойдет, в то время как шаблон остается тем же самым для шаблона-сопоставителя. Я хотел бы подчеркнуть, что это единственная цель. Часто люди используют его также как механизм эвакуации для шаблона-шаблона, где вместо этого следует использовать Verbatim. Это работает, но концептуально неправильно.

Одна очень хорошая учетная запись в процессе оценки, и все это - книга Дэвида Вагнера, "Энергетическое программирование с Mathematica" - ядро, которое было написано в 1996 году для версии 3, но большинство, если не все обсуждения, остаются в силе сегодня, Это печально увы, но вам, возможно, повезло на Amazon (как и несколько лет назад).

Ответ 2

Ответ на вопрос Леонида Шифрина довольно приятный, но я хотел коснуться Defer, который действительно полезен только для одной вещи. В некоторых случаях приятно иметь возможность напрямую конструировать выражения, которые не будут оцениваться, но что пользователь сможет легко редактировать; основным примером такого поведения является палитра кнопок, которую вы можете использовать для вставки выражений или шаблонов выражений во входные ячейки, которые пользователь может затем редактировать по мере необходимости. Это не единственный способ сделать это, и для некоторых более сложных приложений вам нужно попасть в волосатый мир MakeBoxes, но для основ Defer будет хорошо работать.