In recent thread was raised the question: why anonymous pure functions Function[body] (or body &) do not rename symbols in nested scoping constructs while pure functions with named parameters Function[{vars}, body] do rename them as seen from the following example:
lhs_ :> # &@arg
Function[rhs, lhs_ :> rhs]@arg
lhs_ :> arglhs$_ :> arg
(in the second case lhs is renamed to lhs$).
The provided explanation (first given in the comment) states that pure function with no named arguments isn't a scoping construct, hence localization of variables in the nested scope isn't performed. This looks as kind of obvious since there is no need to localize variables inside of a construct which doesn't use variables itself (anonymous pure functions use only Slot).
But when trying to find where it is stated in the official Documentation, I was confused: the modern Documentation seems to state the opposite (although all the linked examples are only about the form Function[{vars}, body]), emphasis is mine:
Functionconstructs can be nested in any way. Each is treated as a scoping construct, with named inner variables being renamed if necessary. »
At the same time Leonid Shifrin notes in his book "Mathematica programming: an advanced introduction" (emphasis is mine):
It is important to note that there is no fundamental difference between functions defined with the
#-¬ation and functions defined with theFunctioncommand, in the sense that both definitions produce pure functions. There are however several technical differences that need to be mentioned.The first one is that the
Function[{vars},body]is a scoping construct, similar toModule,Block,Withetc.
what implies that only the form Function[{vars},body] is a scoping construct, not the form defined with the # - & notation.
Let us make the things clear: is the form Function[body] (and equivalent forms body & and Function[Null, body]) a scoping construct or not? I ask both for authoritative references and for rational analysis of the situation.
Function[x, x*#] &[arg]we have access to the parameters of both functions at the same level. Of course it uses named parameter along with anonymous. If not scoping construct, what definition better describes the nature of# &? – Alexey Popkov Aug 23 '16 at 12:20#-&style of functions essentially macros. The other side of that is that their nesting capabilities are more limited. In your example, you have 2 functions, and you had to use named parameter syntax for one of them precisely because you can't achieve proper nesting using only slots. – Leonid Shifrin Aug 23 '16 at 13:23Slotform and the form with named parameters: the former is merely a substitution construct whereSlots are simply placeholders, but the latter is a true scoping construct very similar toWith(I feel the word "macro" too imprecise since Visual Basic programs in MS Office are also called macroses). Is it correct? – Alexey Popkov Aug 23 '16 at 13:54Function[x, Function[y, x + y]]as#[#2[1] + #3] &[Function, Slot, #] &, anyone who does so should probably be shot... ducks :) – WReach Aug 23 '16 at 14:44#[#2[1] + #3] &[Function, Slot, #] &the first#isn't bound to the first argument of the outerFunction. This again raises my confusion: isn't it a scoping? Could you clear up? – Alexey Popkov Aug 23 '16 at 19:57Functions in that expression, the inner one builds anotherFunctionat run-time. My point is about working of the outerFunction: theSlots of the inner one aren't filled from the outer and it looks for me as a kind of scoping. – Alexey Popkov Aug 23 '16 at 20:21Slotpassed to the outer function as an argument is just an inert expression without any interpretation. – Leonid Shifrin Aug 23 '16 at 20:23FullFormisFunction[Function[Slot[1][Plus[Slot[2][1], Slot[3]]]][Function, Slot, Slot[1]]]. There indeed already exists the innerFunction! It already has some arguments but it exists! – Alexey Popkov Aug 23 '16 at 20:26x+y). In WReach's example, this is not the case: the#in the outer function is bound to the passed argument, while#, #2 and #3of the inner function are bound toFunction,Slot, and#(which by then is already replaced with the passed argument), respectively. Scoping problem is avoided by replacing nesting in space with nesting in time. – Leonid Shifrin Aug 23 '16 at 20:34#: one is bound to the innerFunction's first argument (which is verbatimFunction) and one is bound to the outerFunction's argument (arbitrary), but both are inside of the outerFunction. So the#of the innerFunctionis shielded from the outer. I'm sure I misunderstand something but I feel this as a kind of scoping. – Alexey Popkov Aug 23 '16 at 20:46# &[a] + # &@b(simple nesting ofFunctions). It is sufficient to demonstrate that the statement "the slot parameters are visible from anywhere" isn't correct. And this is what make me feeling that we have a kind of scoping here. – Alexey Popkov Aug 23 '16 at 21:24