11

This is a rather general question, which I fail to answer myself. I guess it is mainly due to my insufficient knowledge of the precise terms.

If I understand correctly, the following are equivalent:

f = Function[u, 3 + u]
f = Function[3 + #]
f = (3+#) &
f[x_]:=3+x

In all cases f[a] would yield 3+a. Similarly, f[a] is equivalent to f@@{a}.

I have mainly two questions:

  1. What is the right term to call the shorter version, i.e. the version where one uses @@, #, & etc.?
  2. When should I prefer the one method and not the other? It seems like many answers given around MA.SE uses the "shorter version". What are the advantages and disadvantages...

Bonus question: Note my first question. I hope I could get more fishing rods and less fish. In other words, what is the official term for these two notions? Where are can I find documentation of these differences? The examples I presented in the this questions are merely examples, and I try to understand where can I rigorously study these notions and similar ones.

Dror
  • 1,841
  • 17
  • 19
  • 2
    Your questions are answered there Functions vs patterns and there f(a)vs.f@a – Kuba Oct 10 '13 at 13:28
  • 1
    @m_goldberg You probably meant to say that the first 3 produce OwnValues. But I think, this observation actually does not clarify matters - the fact that the function in the first 3 cases is stored in a variable is of secondary significance, since Function-s can be also used directly without being stored anywhere. – Leonid Shifrin Oct 10 '13 at 13:32
  • 1
    'Apply' (@@) is often just used when it is convenient. For example if you first generate a list using Table and then want the elements of that list to be arguments of your function. Like in f@@Table[i,{i,3}]. Also sometimes Apply is used to circumvent attributes like HoldAll. For example you can write Hold@@{1+2}, which evaluates to Hold[3], which is not the same as Hold[1+2] which just evaluates to itself. Some part of your question seems to be about notation, as two lines of code you suggest have the same FullForm. Ah there is too much to this question I can't make a point :P – Jacob Akkerboom Oct 10 '13 at 13:34
  • 3
    To the closers: this question is not exact dupe, because the answers linked do not fully explain the difference between long and short forms - which is not only in precedence. – Leonid Shifrin Oct 10 '13 at 13:34

4 Answers4

21

The brief forms /@, and @@@ are not exactly equivalent to the full forms of these operations, and also f[x] is not exactly equivalent to either of f[#]&[x] or f @@ {x}.

I will mention two aspects of the problem, but there likely are more (of course, in addition to the precedence - related aspect, already extensively described in the linked past discussions).

Evaluation

Consider the following example:

Hold[Print[1]]

which evaluates trivially to itself. However, the other forms you mentioned:

Hold @@ {Print[1]}

or

Hold[#] & [Print[1]]

will lead to evaluation leaks (Print will be evaluated).

One can probably come up with some contrived examples of other differences of a similar kind, but generally it is enough to say that these forms define different evaluation routes, so with enough effort, we can generate all kinds of differences. It is another matter that for most practical cases, such differences either are not there or don't matter.

Heads option

The main point here is that the brief forms like f @@@ expr and f @@ expr are parsed as Apply[f,expr,{1}] and Apply[f,expr], respectively, and do not allow one to explicitly pass the Heads option. Therefore, they will always use the global value for this option. And, should anyone change that option globally, there may return different results (from what one would normally expect) - just as the equivalent literal forms I mentioned above do.

You can do the following experiment (make sure you don't have any unsaved work):

SetOptions[Apply, Heads -> True] 

Then (taking this example from the help page for Apply):

f @@@ p[x][q[y]]

(* f[y][f[y]] *)

but the explicit literal form allows to pass the option explicitly:

Apply[f, p[x][q[y]], {1}, Heads -> False]

(* p[x][f[y]] *)

A similar situation is with Map and @@. I have described this in more detail here. Basically, you can't specify the Heads option when you use the short forms.

Note that resetting Heads option globally, as I did here, is strongly discouraged and can lead to disastrous consequences.

SetOptions[Apply, Heads -> False] 
Leonid Shifrin
  • 114,335
  • 15
  • 329
  • 420
  • 5
    I thought it would be interesting to note that I forgot to actually reset the Heads option in my workspace back to False, and was punished by a debugging nightmare which lasted for a good hour. I was lucky enough that the Apply on level one was, in this case, in my own code :) So, the lesson once again is that (re)setting options globally is bad, and particularly so for functions as fundamental as Map and Apply. – Leonid Shifrin Oct 10 '13 at 16:27
  • Leonid, you sure do hang onto your kernel sessions, then :-) – Yves Klett Oct 10 '13 at 19:24
  • Leonid, I just read the last paragraph from the link to your book you provided above and now I'm wondering: Is that the convention you use when you write packages, i.e., not using shorthand notation and explicitly specifying Heads -> False? – sebhofer Oct 10 '13 at 20:58
  • 1
    @sebhofer Alas, I have to confess that I don't. The right thing to do perhaps would be to define your own aliases for Map and Apply which explicitly pass the option, and use them, but I usually am too careless. I am sure that resetting this option globally may / will cause severe problems, because I am sure that a lot of internal code also did not pass these options explicitly. That said, explicitly specifying Heads -> False is a right thing to do if you want you code really bulletproof (but surely not the only such thing). – Leonid Shifrin Oct 11 '13 at 08:30
  • Leonid, you make some excellent points and I hope that will prevent many people from falling into these traps. However, I am a bit confused. First of all, SetOptions[Apply, Heads -> True];f @@@ {{1, 2}, {3, 4}, {5, 6}} gives me {f[1, 2], f[3, 4], f[5, 6]}, and not f[5, 6][f[1, 2], f[3, 4], f[5, 6]]. The latter also doesn't make much sense to me, as f[5,6] seems like a weird new Head. Furthermore I dislike the sentence: "The brief forms ... are not exactly equivalent to the full forms of these operations". After reading this, I thought your point would be that setting the option (...cont) – Jacob Akkerboom Oct 11 '13 at 11:57
  • for Apply would not change the behavior @@@ (so I was quite shocked ;) ). Of course I now see that your point is that using the "fully written form" gives you more power/flexibility/robustness, as it allows you to set the option locally (explicitly, from the robustness perspective). I am afraid other people will be confused in the same/a similar way. Maybe it is nice to add explicitly that two expressions with the same FullForm will always evaluate the same, maybe even adding that you can test this like: HoldComplete[f = Function[3 + #]] == HoldComplete[f = (3 + #) &]. – Jacob Akkerboom Oct 11 '13 at 12:11
  • Of course equivalent (which you use in the full form sentence) can have many meanings. So of course this is not a matter of right or wrong but a matter of getting the point across clearly :). Also I like that you made this a community wiki answer. I will edit things myself if you agree with my points :). – Jacob Akkerboom Oct 11 '13 at 12:14
  • Just for fun: Count[#, Part, Infinity, Heads -> True] & /@ {HoldComplete[ a[[1]][[2]]], HoldComplete[a[[1, 2]]]}. What is equivalent depends on the context I guess :P. – Jacob Akkerboom Oct 11 '13 at 12:22
  • @JacobAkkerboom Sorry for keeping you waiting. Answering to your comments require some time which I don't have at the moment, but I will do that later tonight. – Leonid Shifrin Oct 11 '13 at 14:16
  • @JacobAkkerboom So, I did check, and you are right - my example with @@@ does not return the unusual head, as I reported (I was using the development version, this may as well be a bug there, not sure). Anyway, I replaced the example with a better one (taken directly from Help), and added a paragraph explaining things a bit more. See if you like this better. And thanks for bringing this up. – Leonid Shifrin Oct 11 '13 at 21:19
  • @LeonidShifrin Isn't SetOptions bad practice anyway? In the FrontEnd one can use CurrentValue instead and for Kernel functions it is not really needed I think (but I may be wrong). – Rolf Mertig Oct 11 '13 at 21:58
  • @RolfMertig Yes, I think it is a bad practice. I never use SetOptions myself. – Leonid Shifrin Oct 12 '13 at 10:08
9

If you do a performance test (say, using a million random numbers), you'll find that f = (3+#) & is the fastest. f[x_]:=3+x is significantly slower.

One way to think of @@ (i. e. Apply) is as "replace Head". Because that's exactly what it does. It removes the Head and puts whatever other Head you have provided. Very practical, but not always run-time efficient. Just compare Plus @@ somelist with Total, or even Tr @ somelist.

Also, if you look at Apply in http://reference.wolfram.com/legacy/flash/ you can see quite visually that Apply means "replace Head".

Kuba
  • 136,707
  • 13
  • 279
  • 740
Andreas Lauschke
  • 4,009
  • 22
  • 20
5

These are all functionally equivalent forms of a Pure Function, sometimes called an anonymous function.

body[#] &

I use the operator form body[#]& when there is only one argument, but you can define a more complicated body using #[[2]] (Part) and #2 (Slot) used with List and Sequence arguments respectively.

Function[body[#]]

The full form Function[body[#]] is useful when you are having problems with precedence including other functions into your body. Compare

f@g[#] &@3 // Trace
f@Function[g[#]]@3 // Trace

Usually I use Pure Functions to apply several operations sequentially. I might even string together Built-In functions, user defined functions, and Pure Functions in a one-liner. But if I need to compute several side-calculations using different parts of several input variables, and then combine their results, I might go for

Function[vars, body[vars]]

where body includes a 'Module'. The only time I would do that is if I needed a complex operation which I only need once. Otherwise I would just make a user defined function through setting its DownValues

f[vars_]:=body[vars]

Whether I use Apply vs Prefix depends on whether I have a single List of arguments or several arguments in a Sequence.

f@Sequence[a, b] == f[a, b]
f @@ List[a, b] == f[a, b]
f@List[a, b] == f[{a, b}]
Timothy Wofford
  • 3,803
  • 2
  • 19
  • 24
  • I prefer Composition for a sequence of operations, but this is ofc subjective. – Kuba Oct 11 '13 at 07:21
  • How does Composition work? Does it execute each function in turn, or does it compose a full form function, with all the command arguments properly nested, and apply that? – Timothy Wofford Oct 11 '13 at 12:25
  • There is only the last result. If you want to get them all you can use something like FoldList[#2 @ # &, var, {functionlist}] – Kuba Oct 11 '13 at 12:33
  • I think you missed my question. Suppose that you have something like Composition[f,Apply[g,#]&,h][x]. Would h[x] get executed? Let's find out. With h[x_] := CompoundExpression[CellPrint[x], yes[x]] we try Composition[f,Apply[g,#]&,h][x] and see that h[x] does get executed, so Composition applies each function in turn rather than composing first and applying the result. – Timothy Wofford Oct 11 '13 at 13:28
  • Ah, I wasn't sure what you are asking. That's good point, I think it is first composing and them applying. However I'm not sure if it changes anythig (I've failed to produce different results). – Kuba Oct 11 '13 at 13:39
  • @TimothyWofford one exception to this is when you pass Identity to Composition. Composition[g, Identity, f] -> Composition[g, f]. Note also that Composition dumps all its arguments in a nested way on an(other) argument at once, whereas FoldList (or ComposeList) really write the functions one by one. – Jacob Akkerboom Oct 11 '13 at 13:46
2

In answer to your first question, you can refer to the various special forms of input depending on where and how it is used in the expression. Mathematics and Mathematica both use forms such as prefix, infix and postfix form. You can read more here: Special ways to Input Expressions

For completeness, I'll show several obvious examples:

Prefix form

  • f(x): Here f is the prefix operator

Infix form

  • a + b: Here + is the infix operator because it sits between its arguments

Postfix form

  • 5!: Here ! comes after the 5 on which it is operating.

It is probably worth mentioning that, regardless of the input form used, Mathematica translates all input into a standard prefix form: Head[argument1, argument2, ...]

TransferOrbit
  • 3,547
  • 13
  • 26