Re: What does & mean?
- To: mathgroup at smc.vnet.net
- Subject: [mg107237] Re: What does & mean?
- From: Leonid Shifrin <lshifr at gmail.com>
- Date: Sat, 6 Feb 2010 03:24:59 -0500 (EST)
- References: <201002041126.GAA29847@smc.vnet.net> <hkgks4$6p9$1@smc.vnet.net>
Richard,
>
> Leonid's confusion relates to the pseudo-definition of a "function" by
> pattern matching using
>
> fn[arg_]:= .......
>
> and the definition of a true function by
>
> fn= Function[{arg}], ......] or the brief but obscure ...#..& notation...
> fn = ....#.... &
>
> There is a widely held but technically bogus equivalence in the minds
> of Mathematica users, so Leonid's not alone..
>
> In particular, there is no pattern matching going on in the fn= ... case,
> and the SetAttribute[fn, HoldAll] has no effect whatsoever.
>
Can it be that you are not aware of the syntax of pure functions in
Mathematica which allows to set Hold-attributes (Function[vars,body,
HoldAll] for instance)? But more to the point.
I think it is you who is being confused this time, at least regarding the
main point and purpose of my post. I did not give any "explanation", but
stated the behavior and demonstrated it. In my post, I did not attempt to
compare pattern-defined and pure functions, I just stated one particular
peculiarity of the interplay between evaluation and *pure* functions in
Mathematica. If you'd care to look at the relevant sections of my book you'd
see that I clearly state that pure and pattern-defined functions are very
different and used for different purposes (In fact, I had a couple of
examples similar to yours to illustrate this).
Now, let me explain in more detail the point of my previous post to you and
anyone else interested. First, I repeat my previous code to make it
self-contained:
In[2]:= ClearAll[fn];
SetAttributes[fn, HoldAll];
fn[arg_] :=
Switch[Head[Unevaluated[arg]], Print, "You want to print", Times,
"You want to multiply", _, "I have no idea what you want to do"];
In[5]:= fn[Print["*"]]
Out[5]= "You want to print"
In[6]:=
fn[#] &@Print["*"]
During evaluation of In[6]:= *
Out[6]= "I have no idea what you want to do"
Now, please have a look at the FullForm:
In[7]:= FullForm[fn[#]&]
Out[7]//FullForm= Function[fn[Slot[1]]]
What we see is that <fn> gets wrapped in a pure function. When parameters
are passed to fn[#]&, there are two stages then. First, they are passed to
an outer pure function Function, which in turn evaluates (or not, depending
on its attributes) them and then calls <fn> as a (possibly part of)
evaluation of its body, with these parameters.
Second, parameters are then handed to <fn> (in evaluated form or not - this
depends on the attributes of our external pure function), and their further
evaluation is then governed by the attributes of <fn>.
My point was that if we want parameters held, we must ensure this during
both stages, while #-& based pure functions do not do that, since body[#]&
is a short-hand for Function[body[Slot[1]], and this form of pure function
does not imply Hold-attributes. We'd need Function[Null,
body[Slot[1]],HoldAll] or Function[{par},body[par],HoldAll] (or other
Hold-attribute) instead.
Therefore, for pure functions expressed with #-& notation, parameters always
get evaluated inside Function (stage 1) before they are used in evaluation
of its body, regardless of the properties of the body (attributes of <fn>
here).
>From the end-user viewpoint, the pitfall is that if the user counts on <fn>
holding its arguments and adds a seemingly innocent syntax fn[#]&, she is
in for a big surprise. This is why I cited the relevant part of the
documentation which states the equivalence of fn and fn[#]& and ignores this
subtle point, potentially confusing the users who are unaware of this.
Now, here is what is needed to avoid it:
In[8]:= Function[Null, fn[#], HoldAll][Print["*"]]
Out[8]= "You want to print"
In this case, the presence of HoldAll in a pure function prevented
evaluation of the passed parameter, and it safely "arrived" at <fn> in
unevaluated form. But then again, this form of pure function requires
Function and can not be expressed with #-&.
In fact, there can be cases when this behavior is desirable, and this
construct may be used intentionally. In the following toy situation,
In[9]:= f[x_, y_] := (x - y)^2;
In[10]:= Block[{f},
Hold[Evaluate[f[1 + 2 + 3, 4 + 5 + 6]]]]
Out[10]= Hold[f[6, 15]]
we used Block to get the result as above (partially evaluated), and
Hold[Evaluate[]] construct to evaluate the body of Hold while <f> is
blocked. The same can be achieved with #-&
In[11]:= Block[{f},
Hold[#] &@f[1 + 2 + 3, 4 + 5 + 6]]
Out[11]= Hold[f[6, 15]]
This example is of course artificial, but there are more interesting cases
where this trick is useful.
Once again, the whole discussion is about peculiarities of *pure* function
syntax and evaluation in Mathematica, and this has nothing to do with
pattern-defined functions, which I just used in supporting code for
convenience. Here is a version which does not use pattern-defined functions
at all, but otherwise behaves in exactly the same way for the purposes of my
discussion, and suits me just as well:
In[12]:=
fn1 =
Function[{arg},
Switch[Head[Unevaluated[arg]], Print, "You want to print", Times,
"You want to multiply", _, "I have no idea what you want to do"],
HoldAll];
In[14]:= fn1[#] &@Print["*"]
During evaluation of In[14]:= *
Out[14]= "I have no idea what you want to do"
In[15]:= Function[Null, fn1[#], HoldAll][Print["*"]]
Out[15]= "You want to print"
To my mind, this explanation should have left no room for further
ambiguities, both in terms of what happens and what I meant. By the way, I
encountered this kind of effects all too many times in practice, so this is
not something I am just theorizing about.
Finally, I have a stylistic suggestion that before you publicly post other
messages dismissing some other poster's comments in such a definitive tone,
you first care to study the case under discussion and those posts more
thoroughly than you did it this time. I highly respect you for being one
of the Lisp / CS experts, and I'd prefer to keep it that way.
Regards,
Leonid
>
> (aside: Programming with "pure functions" in Mathematica follows from its
> heritage in Lisp, where Function[{x,y},x+y] or #1+#2& more briefly, would
> be written as (lambda(x y)(+ x y)). Further use of pure functions can be
> viewed in the literature on Lisp. )
>
> To see that the two forms are different most simply, try
>
> f[x_]:=Hello[x]
> g=Hello[#]&
>
> f[1] is the same as g[1], namely Hello[1] but
>
> f[1,2,3] returns Hello[1]
> g[1,2,3] returns g[1,2,3]
>
>
- Follow-Ups:
- Re: Re: What does & mean?
- From: Canopus56 <canopus56@yahoo.com>
- Re: Re: What does & mean?
- References:
- Re: What does & mean?
- From: Bill Rowe <readnews@sbcglobal.net>
- Re: What does & mean?