Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using nested slots (#)

Suppose I want to construct something like

Array[#1^#2 == 3 &, {3, 3}] 

And now I want to replace the "3" with a variable. I can do, for example:

f[x_] := Array[#1^#2 == x &, {x, x}]  

The question is: Is there a way using only slots and & as the functional notation?

like image 252
Dr. belisarius Avatar asked Feb 07 '11 10:02

Dr. belisarius


People also ask

What is the purpose of slots in Vue?

Slot props allow us to turn slots into reusable templates that can render different content based on input props. This is most useful when you are designing a reusable component that encapsulates data logic while allowing the consuming parent component to customize part of its layout.

What are scoped slots?

Scoped slots allow you to pass a template to the slot instead of passing a rendered element. It's called a "scoped" slot because although the template is rendered in the parent scope, it will have access to certain child data. For example, a component child with a scoped slot might look like the following.


3 Answers

Not really the answer to the original question, but I noticed that many people got interested in #0 stuff, so here I put a couple of non-trivial examples, hope they will be useful.

Regarding the statement that for nested functions one should use functions with named arguments: while this is generally true, one should always keep in mind that lexical scoping for pure functions (and generally) is emulated in Mathematica, and can be broken. Example:

In[71]:= 
Clear[f,g];
f[fun_,val_]:=val/.x_:>fun[x];
g[fn_,val_]:=f[Function[{x},fn[#1^#2==x&,{x,x}]],val];
g[Array,3]

During evaluation of In[71]:= Function::flpar: Parameter specification {3} in  
   Function[{3},Array[#1^#2==3&,{3,3}]] should be a symbol or a list of symbols. >>
During evaluation of In[71]:= Function::flpar: Parameter specification {3} in 
   Function[{3},Array[#1^#2==3&,{3,3}]] should be a symbol or a list of symbols. >>

Out[74]= Function[{3},Array[#1^#2==3&,{3,3}]][3]

This behavior has to do with the intrusive nature of rule substitutions - that is, with the fact that Rule and RuleDelayed don't care about possible name collisions between names in scoping constructs which may be present in expressions subject to rule applications, and names of pattern variables in rules. What makes things worse is that g and f work completely fine when taken separately. It is when they are mixed together, that this entanglement happens, and only because we were unlucky to use the same pattern variable x in the body of f, as in a pure function. This makes such bugs very hard to catch, while such situations do happen sometimes in practice, so I'd recommend against passing pure functions with named arguments as parameters into higher-order functions defined through patterns.

Edit:

Expanding a bit on emulation of the lexical scoping. What I mean is that, for example, when I create a pure function (which is a lexical scoping construct that binds the variable names in its body to the values of passed parameters), I expect that I should not be able to alter this binding after I have created a function. This means that, no matter where I use Function[x,body-that-depends-on-x], I should be able to treat it as a black box with input parameters and resulting outputs. But, in Mathematica, Function[x,x^2] (for instance) is also an expression, and as such, can be modified like any other expression. For example:

In[75]:= 
x = 5;
Function[Evaluate[x],x^2]

During evaluation of In[75]:= Function::flpar: Parameter specification 5 in Function[5,x^2] should 
  be a symbol or a list of symbols. >>
Out[76]= Function[5,x^2]

or, even simpler (the essence of my previous warning):

In[79]:= 1/.x_:>Function[x,x^2]

During evaluation of In[79]:= Function::flpar: Parameter specification 1 in Function[1,1^2] should 
  be a symbol or a list of symbols. >>

Out[79]= Function[1,1^2]

I was bitten by this last behavior a few times pretty painfully. This behavior was also noted by @WReach at the bottom of his post on this page - obviously he had similar experiences. There are other ways of breaking the scope, based on exact knowledge of how Mathematica renames variables during the conflicts, but those are comparatively less harmful in practice. Generally, I don't think these sorts of things can be avoided if one insists on the level of transparency represented by Mathematica expressions. It just seems to be "over-transparent" for pure functions (and lexical scoping constructs generally), but on the other hand this has its uses as well, for example we can forge a pure function at run-time like this:

In[82]:= Block[{x},Function@@{x,Integrate[HermiteH[10,y],{y,0,x}]}]

Out[82]= Function[x,-30240 x+100800 x^3-80640 x^5+23040 x^7-2560 x^9+(1024 x^11)/11]

Where the integral is computed only once, at definition-time (could use Evaluate as well). So, this looks like a tradeoff. In this way, the functional abstraction is better integrated into Mathematica, but is leaky, as @WReach noted. Alternatively, it could have been "waterproof", but perhaps for the price of being less exposed. This was clearly a design decision.

like image 67
Leonid Shifrin Avatar answered Oct 17 '22 06:10

Leonid Shifrin


How about

Map[Last, #] & /@ Array[#1^#2 == #3 &, {#, #, #}] &[3]

Horrendously ugly element extraction, and very interestingly Map[Last, #]& gives me a different result than Last /@. Is this due to the fact that Map has different attributes than &?

like image 4
Timo Avatar answered Oct 17 '22 06:10

Timo


I guess you know what the documentation says about nested pure functions.

Use explicit names to set up nested pure functions (for example):

Function[u, Function[v, f[u, v]]][x]

Anyway, here's the best I could come up with without following the above advice:

f[x_] := Array[#1^#2 == x &, {x, x}]
g = Array[With[{x = #}, #1^#2 == x &], {#, #}] &

g is functionally identical to your original f, but is not really better than the recommended

h = Function[x, Array[#1^#2 == x &, {x, x}]]
like image 3
Simon Avatar answered Oct 17 '22 07:10

Simon