MathGroup Archive 2010

[Date Index] [Thread Index] [Author Index]

Search the Archive

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]
>
>



  • Prev by Date: Re: Inserting a position-limited Locator inside a Manipulate
  • Next by Date: Using matrix-form matrices and vectors in function definitions;
  • Previous by thread: Re: What does & mean?
  • Next by thread: Re: Re: What does & mean?