Scoping and Evaluation Control
Module, Block, and With
The three scoping constructs look alike but work differently:
x = 10;
f[] := x
Module[{x = 20}, f[]]
Block[{x = 20}, f[]]
With[{c = 5}, c^2]
10
20
25
- Module (lexical scoping) renames its variables to unique symbols
like
x$1234, so code outside the body — heref— never sees them. Use it for ordinary local variables. - Block (dynamic scoping) temporarily gives the global
xa new value while the body runs, so everything called from the body sees it. Use it to change a setting temporarily, such asBlock[{$RecursionLimit = 5000}, ...]. - With replaces the names with constant values before the body is evaluated — fast, and the values can't be changed.
With is also how you insert a value into held code:
With[{n = 3}, Function[y, y^n]]
Function[y, y^3]
Evaluation order
Normally the Wolfram Language evaluates the head, then each argument,
then applies definitions — repeating until nothing changes. Trace
shows the steps:
Trace[2 + 3*4]
{{3 4, 12}, 2 + 12, 14}
Holding evaluation
Hold[1 + 2]
ReleaseHold[Hold[1 + 2]]
Hold[Evaluate[1 + 2]]
Attributes[Plus]
Hold[1 + 2]
3
Hold[3]
{Flat, Listable, NumericFunction, OneIdentity, Orderless, Protected}
Holdkeeps its argument unevaluated;ReleaseHoldremoves it.Evaluateforces evaluation inside a held position.- Attributes change how a function evaluates:
Orderless(argument order doesn't matter),Flat(associative),Listable(maps over lists),HoldAll/HoldFirst/HoldRest(arguments aren't evaluated first),Protected(can't be redefined).
Giving your functions attributes
clip[v_] := If[v > 5, 5, v]
clip[{1, 7, 3}]
SetAttributes[clip, Listable]
clip[{1, 7, 3}]
If[{1, 7, 3} > 5, 5, {1, 7, 3}]
{1, 5, 3}
Without Listable, the whole list was passed in and the comparison
{1, 7, 3} > 5 couldn't be decided, so If stayed unevaluated. With it,
clip is applied to each element automatically.
A function with HoldAll receives its arguments as code — how you'd
write your own control structure:
SetAttributes[unless, HoldRest];
unless[cond_, body_] := If[!cond, body]
unless[1 > 2, Print["ran"]]
unless[1 < 2, Print["not printed"]]
ran
Because of HoldRest, Print[...] isn't evaluated until If decides to.
Common mistakes
- Using
Blockfor local variables — any function called from the body that uses the same global name is affected. Default toModule. - Forgetting
EvaluateinPlot[Evaluate[Table[x^n, {n, 3}]], {x, 0, 1}]:Plotholds its first argument, so without it the curves are computed but styled as a single function.