Модуль Mathematica против With или Block - Guideline, эмпирическое правило для использования?
Леонид написал в главе IV своей книги: "... Модуль, Блок и С. Эти конструкции подробно объясняются в" Математической книге "и" Математической помощи ", поэтому я скажу несколько слов о них здесь..."
Из того, что я прочитал (смог найти), я все еще в темноте. Для упакованных функций я (просто) использую модуль, потому что он работает, и я знаю конструкцию. Однако это не лучший выбор. Мне не совсем ясно (из документации), когда, где и зачем использовать С (или Блок).
Вопрос. Есть ли правило большого пальца/рекомендации о том, когда использовать модуль, С или Блок (для функций в пакетах)? Существуют ли ограничения по сравнению с модулем? Документы говорят, что С быстрее. Я хочу иметь возможность защищать my = choice = для модуля (или другой конструкции).
Ответы
Ответ 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
немного быстрее, чем вы действительно имеете константы, а не переменные.
Ответ 4
Я хотел бы упомянуть, что официальная документация о разнице между Block
и Module
доступна в http://reference.wolfram.com/mathematica/tutorial/BlocksComparedWithModules.html.