Loops and Scoping
For most simple tasks (i.e. most computations a chemist has to perform), making a notebook with a bunch of input and output cells is sufficient and possibly even best.
However, sometimes the task at hand is not so simple and so we'll need to progress to more complex structures.
Table and Do
Both Table
and Do
list over a range or a set of inputs and apply a function, example:
Table[i*i, {i, 10}]
(*Out:*)
{1, 4, 9, 16, 25, 36, 49, 64, 81, 100}
Table[i*i, {i, {a, b, c, d, e} }]
(*Out:*)
{a^2, b^2, c^2, d^2, e^2}
The difference is that Table
returns a List
while Do
returns either Null
or anything returned from Return
Usually this means one wants to use Table
, however this behavior gives Do
two distinct advantages. The first is that Table
must return something at every step, while Do
used in conjunction with Reap
and Sow
need not. For example let's get the prime numbers between 1 and 1000:
Reap[
Do[If[PrimeQ[i], Sow[i]], {i, 1000}]
][[2, 1]]
(*Out:*)
{2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61,
67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137,
139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211,
223, 227, 229, 233, 239, 241, 251, 257, 263, 269, 271, 277, 281, 283,
293, 307, 311, 313, 317, 331, 337, 347, 349, 353, 359, 367, 373, 379,
383, 389, 397, 401, 409, 419, 421, 431, 433, 439, 443, 449, 457, 461,
463, 467, 479, 487, 491, 499, 503, 509, 521, 523, 541, 547, 557, 563,
569, 571, 577, 587, 593, 599, 601, 607, 613, 617, 619, 631, 641, 643,
647, 653, 659, 661, 673, 677, 683, 691, 701, 709, 719, 727, 733, 739,
743, 751, 757, 761, 769, 773, 787, 797, 809, 811, 821, 823, 827, 829,
839, 853, 857, 859, 863, 877, 881, 883, 887, 907, 911, 919, 929, 937,
941, 947, 953, 967, 971, 977, 983, 991, 997}
Table
would return Null
every time there wasn’t a prime meaning we’d have vastly too many outputs.
Secondly and most critically, Do
can go over an infinite range, when used with Break
or Return
which acts like a While[True, body]
loop, but cleaner. In general, Do
can be used in this way whenever While
would have been used. For example:
Do[If[RandomReal[] < .00001, Return[i]], {i, ∞}]
(*Out:*)
210319
This simulates the following loop:
i = 1;
While[RandomReal[] > .00001,
i += 1
];
i
(*Out:*)
184158
But Do
is a cleaner construct, owing to its automatic scoping of the i
and implicit incrementor
Module, With, and Block
Module
, With
, and Block
are called scoping constructs. That is, they let you use a variable or multiple variables without having to change or set them globally, or. This is easiest to show in an example:
Consider the following chunk of code:
a = 2;
squareA[] := (a = a*a);
{squareA[], squareA[], squareA[]}
(*Out:*)
{4, 16, 256}
Then check the current value of a
a
(*Out:*)
256
Now try checking a
in a Module
where the variable a
has been scoped
Module[{a},
a
]
(*Out:*)
a$736
Notice that the value of a
is not its global value. This is because Module
creates its own scope to execute the code in.
This is the basic use of a scoping construct, protecting code from being influenced by the global state.
Each construct has its own peculiarities, but these will be discussed more later. For now, we’ll only discuss Module
as its usage is the clearest.
Module
Module
has the following form:
Module[{var1, var2, ..., varn},
codeBlock
]
where var1, var2, ..., varn
are either simple variable names or variable names with initial values.
Past that, one can write code with Module
just as one would normally.
Consider the following:
Module[{v1, v2 = 10, v3 = 50, v4},
v3 = 10;
v4 = v3*v2;
{v1, v2, v3, v4}
]
(*Out:*)
{v1$739, 10, 10, 100}
The code executes just as one would expect, the only difference being that v1
has been renamed. If one runs the following it becomes clear how Module
works:
Module[
{v1, v2 = 10, v3 = 50, v4},
v3 = 10;
Clear@v4;
{v1, v2, v3, v4}
]
(*Out:*)
{v1$740, 10, 10, v4$740}
All module does is replace each variable in the first argument with the variable name followed by $i
where i
is an integer (given by the value of the global variable $ModuleNumber
when the Module
is executed).