Re: execution model: Function vs. delayed execution

*To*: mathgroup at smc.vnet.net*Subject*: [mg121342] Re: execution model: Function vs. delayed execution*From*: "Oleksandr Rasputinov" <oleksandr_rasputinov at hmamail.com>*Date*: Sun, 11 Sep 2011 07:30:00 -0400 (EDT)*Delivered-to*: l-mathgroup@mail-archive0.wolfram.com*References*: <j4fhvn$2gr$1@smc.vnet.net>

On Sat, 10 Sep 2011 12:34:15 +0100, Alan <alan.isaac at gmail.com> wrote: > Warning: I am a Mathematica newbie and not a CS type, so my vocabulary > may prove clumsy. > > I am used to a deferred execution model of function definition. > Roughly, if I can write code that would be successfully executed outside > a function definition, then I can make it a function body by > appropriately "wrapping" it. > > In Mathematica, I can evaluate the following): > x = {1,1,2} > x=DeleteDuplicates[x]; x > (Note: the redundancy is intentional.) > > Next, I attempt to "wrap" this as follows > Clear[x] > Function[x, (x=DeleteDuplicates[x];x)][{1,1,2}] > > This produces an error: > Set::shape: "Lists {1,1,2} and {1,2} are not the same shape." > > Can you help me understand the execution model that leads to this? > > Thanks, > Alan Isaac > Function employs strict lexical scoping that overrides the HoldFirst attribute of Set: In[1] := Function[x, x = DeleteDuplicates[x]; x][{1, 1, 2}] // Trace Out[1] = { Function[x, x = DeleteDuplicates[x]; x][{1, 1, 2}], {1, 1, 2} = DeleteDuplicates[{1, 1, 2}]; {1, 1, 2}, { { DeleteDuplicates[{1, 1, 2}], {1, 2} }, {1, 1, 2} = {1, 2}, (* <- this gives rise to the message *) { Message[Set::shape,{1, 1, 2},{1, 2}], {Set::shape,Lists `1` and `2` are not the same shape.} << extra tracing omitted >> } } } this is documented via the statement, "Function has attribute HoldAll. The function body is evaluated only after the formal parameters have been replaced by arguments." Using With for comparison: In[2] := With[{x = {1, 1, 2}}, x = DeleteDuplicates[x]; x ] During evaluation of In[2] := Set::shape: Lists {1, 1, 2} and {1, 2} are not the same shape. Out[2] = {1, 1, 2} This is in contrast to Block which implements dynamic scoping (or indeed Module, whose scoping is effectively lexical, but not as directly so as that of With or Function): In[3] := Block[{x = {1, 1, 2}}, x = DeleteDuplicates[x]; x ] Out[3] = {1, 2}