Take the 2-minute tour ×
Mathematica Stack Exchange is a question and answer site for users of Mathematica. It's 100% free, no registration required.

Every time I define a new function, I wonder which construct I should use: true functions obtained by using Function, or rule-based syntax. For example, these are two ways of defining a square function:

square = Function[x, x^2]
(* Alternatively: square = #^2& *)

square2[x_] := x^2

Is there some fundamental difference (e.g. execution efficiency) between the two approaches?

share|improve this question
1  
I don't think there's much of a difference. If a function is sufficiently complicated, I might prefer the second construction over the first one, though. Note that recursive functions are easily done with the second construct, but are a bit tricky to do with the first, as in this Fibonacci example: fib = (If[#1 == 1 || #1 == 2, 1, #0[#1 - 1] + #0[#1 - 2]]) &. –  J. M. Jan 26 '12 at 1:10
4  
A variations of this question have been asked on SO a few times in the past: stackoverflow.com/questions/4187822/…, stackoverflow.com/questions/6333450/…. –  Leonid Shifrin Jan 26 '12 at 11:55

6 Answers 6

up vote 36 down vote accepted
square = Function[x, x^2];
square1 = #^2 &;
square2[x_] := x^2;

DownValues[square]
DownValues[square1]
DownValues[square2]

{}
{}
{HoldPattern[square2[x_]] :> x^2}

Two differences that immediately come to mind are that:

1) functions with down values won't autocompile when you use them in Table, Map, Nest etc. so therefore are less efficient when used that way. e.g.

data = RandomReal[{0, 10}, {10000}];

Timing[Developer`PackedArrayQ[Map[square, data]]]
Timing[Developer`PackedArrayQ[tmp1 = Map[square1, data]]]
Timing[Developer`PackedArrayQ[tmp2 = Map[square2, data]]]

{0.001404, True}
{0.001498, True}
{0.022324, False}

despite tmp1 being packed and tmp2 being unpacked they are equal

tmp1==tmp2
True

but using the pure function gives you a packed list which means faster evaluations and less memory for storage:

N@ByteCount[tmp2]/ByteCount[tmp1]
3.49456

This example used Map but you would observe the same thing with Table, Nest, Fold and so on. As to why this is the case (@Davids question) the only answer I have is the circular one that autocompilation using functions with down values hasn't been implemented. I haven't found out what the difficulties are in implementing this, i.e. whether it hasn't been done because it can't be or because it just hasn't been. Someone else may know and can comment.

2) functions with down values may (in all likelihood will) cause a security warning when present in an embedded CDF.

I'm sure others will be able to expand on this and add many more differences.

share|improve this answer
    
Of course, if the application will involve compiled functions anyway (e.g. numerical work), one would want to use Compile[] directly instead of Function[]. –  J. M. Jan 26 '12 at 1:55
    
What's the reason for 1), or do you have something for further reading? This kind of looks like a good reason to use Function in many cases. –  David Jan 26 '12 at 2:19
    
@David just updated. The only reason I know is not a reason, i.e. because that is what is. –  Mike Honeychurch Jan 26 '12 at 6:47
1  
@Mike Compilation of pattern-based functions would require to compile the entire pattern-macther. While theoretically this might be possible, the task is extremely difficult, because the pattern-matcher has very complex semantics (Attributes, infinite evaluation, various types of global rules, defaults, ...), and Mathematica is an untyped language. So, for all practical purposes, this is plain impossible to do. IMO, intermediate (perhaps more strongly typed) language layer would be needed to make some subset of the rule-based code compilable. –  Leonid Shifrin Jan 26 '12 at 12:38
    
@Leonid thanks for that explanation. –  Mike Honeychurch Jan 26 '12 at 22:00

These two forms may be similar on the surface, but they are very different in terms of the underlying mechanisms invloved. In a sense, Function represents the only true (but leaky) functional abstraction in Mathematica. Functions based on rules are not really functions at all, they are global versions of replacement rules, which look like function calls.

One big difference is in the semantics of parameter-passing. For rules (and therefore functions based on rules), it is more intruding, in the sense that they don't care about the inner scoping constructs, while Function (with named arguments only) will care. Here is an example of what I mean:

Function[{x},Module[{x=2},x]][3]

(*
  ==> 2
*)

while

In[46]:= 
ClearAll[fn,a];
fn[x_]:=Module[{x=2},{Hold[x],x}]
fn[3]

During evaluation of In[46]:= Module::lvset: Local variable specification 
{3=2} contains 3=2, which is an assignment to 3; only assignments to symbols are allowed. >>

Out[48]= Module[{3=2},{Hold[3],3}]

and especially

In[49]:= 
Clear[a];
fn[a]

Out[50]= {Hold[a$840],2}

Another difference I want to mention is that, due to Function with names arguments beaing a leaky abstraction, passing it as an argument to another function is risky. In addition to the mentioned above post by @WReach, which exposes the essence of the problem, see this post for an example of a trouble that one can get into, in a more "realistic" situation.

That said, in many cases one may think of "functions" defined by rules as normal functions. Because of the powerful builtin rule - dispatching mechanism of rule-application, functions based on rules can be overloaded in very powerful ways, which adds expressive power, as noted by @Sal.

Additionally, while this is not often used, one can often use global pattern-based function definitions as local rules, to achieve rather non-trivial things. In this answer, I use this technique to illustrate how one can dynamically generated Mathematica code at run-time, with the ability to test it in the "interpreter" mode. To illusrate the power of this approach here, I will write a (simplistic, sloppy) macro which will remove the Map auto-compilation limitation mentioned by @Mike Honeychurch, at least for simple pattern-based functions:

ClearAll[withGlobalFunctions];
SetAttributes[withGlobalFunctions, HoldAll];
withGlobalFunctions[code_] :=
  With[{rules =   
       Flatten@Cases[ 
         Names["Global`*"], 
         s_ :> ToExpression[s, InputForm, DownValues]]
       },
    ReleaseHold[
       Hold[code] //. {
         HoldPattern[Map[f_Symbol, args__]] :> Map[f[#] &, args], 
         Sequence @@ rules
       }
    ]
];

Now, taking the same setup:

data = RandomReal[{0, 10}, {500000}];

In[114]:= 
Timing[Developer`PackedArrayQ[Map[square,data]]]
Timing[Developer`PackedArrayQ[tmp1=Map[square1,data]]]
Timing[withGlobalFunctions@Developer`PackedArrayQ[tmp2=Map[square2,data]]]

Out[114]= {0.031,True}
Out[115]= {0.015,True}
Out[116]= {0.032,True}

where what happened is that my macro has expanded the call to square2 before Map was used on it. This is quite non-trivial, becuase it was able to expand the cal square2[#] inside a pure function. This is actually the case of a constructive use of the mentioned above leaky functional abstraction - were Function a complete black box, and this would not be possible. Note that the transformation f->f[#]& is not always correct, since it leaks evaluation. I used it here as an example, but if one were to do it for real, more care must be taken.

share|improve this answer
    
+1 for leaky -- boy that reads strangely. –  Mr.Wizard Feb 17 '12 at 9:19

Functions are more concise and generally faster but patterns are a lot more expressive. When you don't need the expressive power of patterns you should probably use functions. I use down values more to set up the high level structure of my program and functions to implement the algorithms. But often I am lazy and use down values out of habit. When I am in exploratory mode I pretty much don't worry about the difference.

This example from the Mathematica docs shows one way down values are more expressive (dynamic programming):

fib[n_] :=
 Module[{f},
  f[1] = f[2] = 1;
  f[i_] := f[i] = f[i - 1] + f[i - 2];
  f[n]
  ]

The fact that you can add conditions and the like are another way patterns are more expressive:

f[x_?EvenQ] := 1
f[x_?PrimeQ] := 2
f[x_ /; x > 21 && x < 99] := 3
f[x_] := 4

Of course, you add conditional logic to functions and get a similar effect.

It's also a good idea to use functions when they are side-effect free and down values when there are possible side-effects but this is not something Mathematica enforces and is more of one of my philosophical preferences that comes from exposure to functional programming languages.

I am not sure why down values cause problems in CDF's and I would hope this gets fixed or lessened in future versions. It seems overly restrictive.

share|improve this answer
    
For novice readers: there is a fair bit of difference between Sal's implementation of the Fibonacci recurrence here, and the pure function implementation I gave in the comments. Sal's implementation caches values by virtue of the f[i_] := f[i] = (* stuff *) construction. This is more efficient for large argument values, but at the expense of some storage. –  J. M. Jan 26 '12 at 5:56
    
Note that the second snippet can alternatively be done in terms of any of If[], Which[], Switch[], or Piecewise[], but the approach Sal gives might be better if the cases involved are a bit more elaborate. –  J. M. Jan 26 '12 at 5:57

The first example (using Function) is called a "pure function" or an "anonymous function". It is used (for example) when you do not want to bother to give a special name to your function. You just describe what it does when applied to its arguments. This is very similar to the pure mathematics

$x\mapsto f(x)$

notation. The emphasis here is on the "abstract" functional aspect (i.e. you think at the function as an object in a functional space).

Typical use is with some kind of options (often from built-in functions) as in:

FixedPoint[(# + 2/# )/2 &, 1`20, SameTest -> (Abs[#1 - #2] < 1*^-10 &)]

where you want to create "on the fly" - without giving a special name - a test function, or in

CellPrint[
 ExpressionCell[x, "Input", 
  CellEvaluationFunction -> (Style[ToExpression[#]^2, Red] &)]]

These are examples from the doc center.

As explained in other answers, its use is less user-friendly, so you will use it (much) less often than the regular

square2[x_] := x^2

style of definition.

share|improve this answer
2  
Note that Mathematica supports a notation that is close to the mathematical one. Try x \[Function] x^2. –  J. M. Jan 26 '12 at 2:53
    
@J.M. Indeed! There is also a palette button for it , if I remember well –  magma Jan 26 '12 at 3:04

I think it is generally a matter of preference.

For my purposes I typically use the second form because it is easier to set up multiple definitions given the same number of inputs and cleaner to perform validation on the inputs. I also find the code easier to understand and debug.

Here is a toy example.

f[x_Integer, y_Integer] := x*y
f[x_List, y_List] := Outer[Times, x, y]
f[___]:= $Failed

Which could be almost equivalently but IMO less cleanly written.

g = Function[{x, y}, 
      Switch[{x, y}, 
        {_Integer, _Integer}, x*y
        , 
        {_List, _List}, Outer[Times, x, y]
        , 
        ___, $Failed]
    ]

I'm at a loss at the moment for how to code that BlankNullSequence bit that would allow g[1] to return $Failed as f[1] would.

One place I often do use the "pure function" style (outside of say graphics options) is when programmatically building up functions.

Here is another toy example that will create a function on the fly that takes 2 or more arguments depending on the inputs to h and when applied to the same number of args, multiplies them. Silly, but you get the idea.

h[arg1_, arg2__] := 
  Block[{x, a},
     x = Table[Unique[a], {Length[{arg1, arg2}]}];
     Hold[Function][x, Times @@ x] // ReleaseHold
  ]

I find this sort of thing more difficult (though not impossible) to do with the f[x_]:= approach.

share|improve this answer

The second form is usually preferred over the first. This is because it is easier to write functions with multiple parameters (rather than #1, #2, ...), it is more straightforward to associate patterns and conditions on the parameters, and to define functions with variable numbers of parameters.

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.