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开发者_如何学Go is: Is there a way using only slots and & as the functional notation?
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.
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 &
?
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}]]
How about With[{x = #1}, Array[#1^#2 == x &, {x, x}]] &
?
Perhaps
Array[#1^#2 &, {#, #}] /. i_Integer :> i == # &[3]
Or
Thread /@ Thread[# == Array[#1^#2 &, {#, #}]] &[3]
精彩评论