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

Модуль Mathematica против With или Block - Guideline, эмпирическое правило для использования?

Леонид написал в главе IV своей книги: "... Модуль, Блок и С. Эти конструкции подробно объясняются в" Математической книге "и" Математической помощи ", поэтому я скажу несколько слов о них здесь..."

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

Вопрос. Есть ли правило большого пальца/рекомендации о том, когда использовать модуль, С или Блок (для функций в пакетах)? Существуют ли ограничения по сравнению с модулем? Документы говорят, что С быстрее. Я хочу иметь возможность защищать my = choice = для модуля (или другой конструкции).

4b9b3361

Ответ 1

Более практическое различие между Block и Module можно увидеть здесь:

Module[{x}, x]
Block[{x}, x]
(*
-> x$1979
   x
*)

Итак, если вы хотите вернуться, например, x, вы можете использовать Block. Например,

Plot[D[Sin[x], x], {x, 0, 10}]

не работает; чтобы он работал, можно было использовать

Plot[Block[{x}, D[Sin[x], x]], {x, 0, 10}]

(конечно, это не идеально, это просто пример).

Другое использование - это что-то вроде Block[{$RecursionLimit = 1000},...], который временно меняет $RecursionLimit (Module не работал бы, переименовывая $RecursionLimit).

Можно также использовать Block для блокировки оценки чего-либо, например

Block[{Sin}, Sin[.5]] // Trace
(*
-> {Block[{Sin},Sin[0.5]],Sin[0.5],0.479426}
*)

т.е. возвращает Sin[0.5], который оценивается только после завершения выполнения Block. Это связано с тем, что Sin внутри Block является просто символом, а не функцией синуса. Вы даже можете сделать что-то вроде

Block[{Sin = Cos[#/4] &}, Sin[Pi]]
(*
-> 1/Sqrt[2]
*)

(используйте Trace, чтобы увидеть, как он работает). Таким образом, вы можете использовать Block для локального переопределения встроенных функций:

Block[{Plus = Times}, 3 + 2]
(*
-> 6
*)

Ответ 2

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

Module[{x}, ...] является самым безопасным и может понадобиться, если

  • Существуют существующие определения для x, которые вы хотите избежать нарушения во время оценки модуля, или

  • Существует существующий код, который полагается на x как undefined (например, код типа Integrate[..., x]).

Модуль также является единственным выбором для создания и возврата нового символа. В частности, по этой причине модуль иногда необходим в продвинутом динамическом программировании.

Если вы уверены, что нет важных существующих определений для x или любого кода, полагаясь на то, что он undefined, то Block[{x}, ...] работает быстрее. (Обратите внимание, что в проекте, полностью закодированном вами, уверенность в этих условиях - разумный стандарт "инкапсуляции", который вы, возможно, захотите применить в любом случае, и поэтому Block часто является правильным выбором в этих ситуациях.)

With[{x = ...}, expr] - единственная область определения, которая вводит значение x внутри Hold[...]. Это полезно и важно. With может быть как быстрее, так и медленнее Block в зависимости от expr и конкретного пути оценки, который выполняется. With менее гибкий, поскольку вы не можете изменить определение x внутри expr.

Ответ 3

Эндрю уже предоставил очень полный ответ. Я просто подвел итог, отметив, что Module предназначен для определения локальных переменных, которые могут быть переопределены в рамках определения функции, а With - для определения локальных констант, чего не может быть. Вы также не можете определить локальную константу, основанную на определении другой локальной константы, которую вы установили в том же самом выражении With, или иметь несколько символов в LHS определения. То есть следующее не работает.

With[{{a,b}= OptionValue /@ {opt1,opt2} }, ...]

Я стараюсь установить сложные определения функций с Module, охватывающим a With. Я установил все локальные константы, которые я могу сначала ввести внутри With, например. Length данных, переданных функции, если мне это нужно, а затем других локальных переменных по мере необходимости. Причина в том, что With немного быстрее, чем вы действительно имеете константы, а не переменные.