5
$\begingroup$

It seems to me that functions defined using a simple pattern and SetDelayed (the usual way to define a "function") should be equivalent in all respects to functions defined using Function: both say what to do with a value provided in a slot, and merely have different methods of designating the slot. But they are not. Observe:

f1[x_] := x^2;
f2 = Function[#^2];
{f1[3], f2[3]}

(* {9, 9} *)

So far, so good. However:

g[ff_Function, y_] := ff[y];
{g[f1, 3], g[f2, 3]}

(* {g[f1, 3], 9} *)

One can be passed around via its symbol and be invoked as a callback, and the other cannot. It would be convenient (and, for the novice programmers I teach, less confusing) to define functions for callbacks with the more transparent SetDelayed notation, rather than with pure function notation.

Clearly, there is some deep difference between these two rules that I do not understand. Perhaps someone wiser than I can illuminate?

$\endgroup$
  • 2
    $\begingroup$ Well, you get what you ordered. By using the pattern _Function in your first argument in g, you only allow the first argument to be a Function - otherwise the definitiion does not apply. Use g[ff_, y_]:=..., and you get what you want in both cases. $\endgroup$ – Leonid Shifrin Mar 14 '15 at 19:24
  • $\begingroup$ Why the close votes? This is a legitimate question, even if the answer is rather simple. $\endgroup$ – Leonid Shifrin Mar 14 '15 at 19:29
  • $\begingroup$ @LeonidShifrin OK, I retracted my close vote. Please consider posting your comment as an answer. $\endgroup$ – C. E. Mar 14 '15 at 19:35
  • 1
    $\begingroup$ @Pickett Re: retracted close vote - thanks. Re: answer - done. $\endgroup$ – Leonid Shifrin Mar 14 '15 at 19:51
  • $\begingroup$ Related: (10175), (22449), (73833) $\endgroup$ – Mr.Wizard Mar 15 '15 at 11:28
10
$\begingroup$

Most functions in Mathematica are actually global rules, with Function being an (very important) exception. Argument patterns in functions defined by rules are typically used as a flexible typing mechanism. You can go from completely untyped definitions (where you use patterns like _, __, etc.), to something in the middle (like e.g. {__List}), to completely strongly typed, like _h, where the head h serves as a type.

In your case, when you define

g[ff_Function, y_] := ff[y];

this definition will only apply if your first argument matches the pattern _Function, that is, has the head Function. If you want your function g to accept any callback function, simply leave this restriction out:

ClearAll[g];
g[ff_, y_] := ff[y];

It is important to keep in mind the rule-based nature of the language, and that for many constructs, which look similar to their analogs in other languages, while such similarity was intentional, the underlying mechanisms behind them may be very different.

$\endgroup$
  • $\begingroup$ Hm, so what I usually think of as a "function" isn't technically a Mathematica function, but rather a rule. That makes sense now. So... If I don't restrict my argument to Function, is there a way to restrict it to things that _act like functions (such as SetDelayed rules), rather than, say, numbers or undefined symbols? In my particular application, I'm overloading a function so that it can take a callback "function" (loosely speaking) or a non-function, but handles them differently. $\endgroup$ – ibeatty Mar 15 '15 at 1:21
  • $\begingroup$ @ibeatty [1/2] I am not aware of a fully robust way to differentiate between functions and other things in Mathematica. Partly this is because for the core evaluator, what we consider functions are no different from other expressions. In other languages, calling a function which evaluator knows nothing about, is an error. In Mathematica, it is not, and the call (expression) is simply returned back. One way I was using before was to use the pattern _Symbol | _Function, but this isn't robust either. For example, people may define SubValues of the form f[a_,b_][x_,y_]:=a+b+x+y, and then ... $\endgroup$ – Leonid Shifrin Mar 15 '15 at 11:02
  • $\begingroup$ @ibeatty [2/2] ... pass f[1,2] as a function. There may be other similar constructs. I seem to remember some discussions about checks for functions, but I can't find them now. The other way would be to use an inert wrapper, e.g. Fun[...], and then place inside this wrapper the function. So then, your definition would look like g[Fun[ff_],y_]:=..., and the caller is responsible for wrapping a function in Fun when passing arguments to g. This, of course, does not prevent the caller from passing a wrong thing inside Fun, but at least it will probably rule out accidental mistakes. $\endgroup$ – Leonid Shifrin Mar 15 '15 at 11:07
  • $\begingroup$ Some more information on strong types in Mathematica is in this discussion. An interesting discussion of differences between Mathematica and traditional languages (the high-level view on them) is inside this answer. $\endgroup$ – Leonid Shifrin Mar 15 '15 at 11:08

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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