31

Pure functions may be handy if you don't want to assign your function a name. For example I would calculate $x(x-1)$ for some numbers $x$ by

In: #(#-1) & /@ {1, 2, 3}
Out: {0, 2, 6}

Is it possible to use patterns in this construction? For example something like

f[x_Integer] := x(x-1)

but then without defining a function f first.

Karsten7
  • 27,448
  • 5
  • 73
  • 134
sjdh
  • 7,757
  • 5
  • 37
  • 47

9 Answers9

22

You could write something like this:

# /. x_Integer :> x (x - 1) & /@ {1, 2, 3}

{0, 2, 6}

WReach
  • 68,832
  • 4
  • 164
  • 269
  • Dang, I was trying to go for this but managed to add an additional layer of complexity :-). – Timo Mar 19 '12 at 14:01
  • 9
    +1. I would however use Replace rather than ReplaceAll, to prevent the rule to apply on deeper levels in case when it does not apply to the top-level. – Leonid Shifrin Mar 19 '12 at 17:45
18

To complement WReach's answer, I suggest that you are actually looking for replacement rules. A function with patterns is effected with replacement rules:

f[x_Integer] := x(x-1)

DownValues[f]
{HoldPattern[f[x_Integer]] :> x (x - 1)}

You you don't need to actually set this definition (DownValue) to use the same rule.

Clear[f]

f /@ {1, 2, Sqrt[7], 0.3} /. {f[x_Integer] :> x (x - 1)}
{0, 2, f[Sqrt[7]], f[0.3]}

I suggest doing the replacement directly, and I recommend using Replace rather than ReplaceAll (/.) if you want something analogous to a pure function. Using /. would result in Sqrt[42] in this example:

Replace[{1, 2, Sqrt[7], 0.3}, {x_Integer :> x (x - 1), x_ :> f[x]}, {1}]
{0, 2, f[Sqrt[7]], f[0.3]}

You can of course do something else with arguments that do not match x_Integer besides wrapping in f. If you want a pure function to map onto individual elements you could use:

Replace[#, x_Integer :> x (x - 1)]& /@ {1, 2, Sqrt[7], 0.3}
{0, 2, Sqrt[7], 0.3}
Mr.Wizard
  • 271,378
  • 34
  • 587
  • 1,371
  • +1 for the note on Replace (I noted that too). Local replacement rules (their semantics) are not entirely equivalent to global rules / definitions. This was partly why I did not take the road taken by @WReach (although I accept that as an alternative and voted for his answer). Whether or not the OP will be satisfied with local replacement rules depends largely on how closely he wants to follow the semantics of functions based on global rules / definitions, I think. – Leonid Shifrin Mar 19 '12 at 17:54
  • With the operator forms (new since V10?), we can simplify the code: Replace[x_Integer :> x (x - 1)] /@ {1, 2, Sqrt[7], 0.3} – Michael E2 Jun 18 '22 at 18:26
9

Four ways from If:

If[IntegerQ@#, # (# - 1), #] & /@ {3, π}
 (* {6, π} *)

If[# ∈ Integers, # (# - 1), #] & /@ {3, π}
 (* {6, π} *)

If[Head@# === Integer, # (# - 1), #] & /@ {3, π}
 (* {6, π} *)

If[MatchQ[#, _Integer], # (# - 1), #] & /@ {3, π}
 (* {6, π} *)

The last two work also with user-defined heads. The 2nd argument to MatchQ can be any pattern.

If you like, you can return the pure function unevaluated on arguments that don't match the pattern:

If[MatchQ[#, _Integer], # (# - 1), Hold[#0][#]] & /@ {3, π}
 (* {6, Hold[If[MatchQ[#1, _Integer], #1 (#1 - 1), 
 Hold[#0][#1]] &][π]} *)

although I don't see a use for it.

I'm not advocating using If, just pointing out what is possible.

Mr.Wizard
  • 271,378
  • 34
  • 587
  • 1,371
JxB
  • 5,111
  • 1
  • 23
  • 40
8

No, this is not possible, for the following reason (in my opinion):

When you define

f[x_Integer] := ...

and evaluate f[Pi] (where Pi is not of type Integer), then the function will stay unevaluated in the form f[Pi]. If you could use a pure function in the hypothetical form of Function[x_Integer, x(x+1)], then of course it could stay unevaluated in the form Function[x_Integer, x(x+1)][Pi], but I am not sure this would be useful. (Well, it might be if you pass it a symbol that you may later replace with an integer.)

Anyway, it is not possible.

There are some ways one can make use of patterns in pure functions (for example through replace rules). So now the question is: what do you want to achieve by using a pattern in a pure function? If it is preventing evaluation, it's not possible. If it's something else, it might be.

Szabolcs
  • 234,956
  • 30
  • 623
  • 1,263
  • I would say that foo & is an anonymous function regardless of whether foo contains replacement rules, If[] statements or other inbuilt functions. The main point being that they are not assigend as a downvalue for a symbol. – Timo Mar 19 '12 at 14:40
  • @Timo Of course, I didn't claim otherwise. Please tell me know if my post is confusing in any way. – Szabolcs Mar 19 '12 at 15:02
  • @Timo If the downvote was given by you, please explain in detail why. I don't understand how your comment relates to my post. – Szabolcs Mar 19 '12 at 15:03
  • 1
    The downvote is from me. The OP question was about using pattern based matching in anonymous functions and your answer starts out with No and you reiterate "not possible" later. As many (myself included) point out this is not the case. WReach has the best example (I even removed my earlier answer that was a less elegant implementation of the same principle).

    Your comment regarding leaving the function unevaluated is valid but not really applicable in the case of pure functions (as you point out yourself).

    Anyway those are my reasons. If they are unreasonable (sry pun) let me know.

    – Timo Mar 19 '12 at 16:48
  • @Timo The pattern the OP gave as an example simply causes the function to stay unevaluated for non-integer arguments. This is not possible with pure functions. Please not that I explicitly say that while evaluation can't be prevented, it is possible to use replacement rules. I asked the OP for clarification about this. I did not give your solution because it is not clear that this is the effect he wants to achieve. – Szabolcs Mar 19 '12 at 17:38
  • 1
    +1 for pointing out the unevaluated behaviour. – JxB Mar 19 '12 at 21:40
7

Map is unnecessary in this case, so the most succinct expression is:

{1, 2, 3} /. x_Integer :> x (x - 1)
rm -rf
  • 88,781
  • 21
  • 293
  • 472
alancalvitti
  • 15,143
  • 3
  • 27
  • 92
6

This is very similar to the answer by Mr.Wizard, but avoids to introduce a named expression and therefore rewriting the function by using Condition:

Replace[_, {_ /; IntegerQ[#] :> # (# - 1), _ :> #}] & /@ {1, 2, 3, x}

{0, 2, 6, x}


A more direct way is to use Switch:

Switch[#,
   _Integer, # (# - 1),
   _, #] & /@ {1, 2, 3, x}

{0, 2, 6, x}

Karsten7
  • 27,448
  • 5
  • 73
  • 134
  • 1
    I personally prefer to avoid using both Map and Replace as both can take a levelspec as needed. I would instead use If[IntegerQ[#], # (# - 1), #] & /@ {1, 2, 3, x} if avoiding named patterns for some reason. – Mr.Wizard May 01 '16 at 23:05
  • @Mr.Wizard I agree and as a single line of code I would not use it as well. But using Map is only part of the example and not the main "patterns in pure function" question. – Karsten7 May 02 '16 at 08:34
  • Well the OP already knew about Slot and Function so, bluntly, I don't see the point of the first method. The Switch code however is a good example of the use of a pattern inside a pure function as requested, so +1 for that. – Mr.Wizard May 03 '16 at 15:57
6

You can return a closure with encapsulated pattern-defined function using some custom assignment operator, like this one:

ClearAll[deff];
SetAttributes[deff, HoldAll];
deff[lhs_ :> rhs_] :=
  Module[{f},
    f[lhs] := rhs;
    f[##] &]

This can be trivially generalized to many rules. You can then use it as

With[{fn = deff[x_Integer :> x*(x - 1)]},
   Map[fn, Range[10]]]

(*    {0, 2, 6, 12, 20, 30, 42, 56, 72, 90}  *)

One problem you still have to solve in this approach is a proper garbage-collection of such functions. You may also want to use some form of memoization for deff, so that it does not produce a brand new pure function every time when called on the same rule (modulo pattern variables names). Both problems are solvable, if not completely trivial. Finally, note that wrapping in a pure function restricts the set of Attributes which can be used, since not all possible Attributes for symbols make sense for a pure function (I did not include attributes here for simplicity).

All in all, while I can see some cases where this may be nice to have, in most cases this is probably more work than it's worth. In fact, in the above approach, it is much easier for deff to return just the generated symbol f itself, which is probably a better solution if you want some auto-generated functions and don't want to bother with the naming. This will also automatically take care of the Attributes issue.

Leonid Shifrin
  • 114,335
  • 15
  • 329
  • 420
  • I'll never say not possible again :-) +1 – Szabolcs Mar 19 '12 at 10:33
  • @Szabolcs Well, strictly speaking, you were right. I just considered the problem a little broader. – Leonid Shifrin Mar 19 '12 at 10:34
  • 5
    I wonder what advantage it would have jumping through all those hoops compared to just defining the function... – Sjoerd C. de Vries Mar 19 '12 at 13:22
  • 2
    I've noticed whenever I answer something on the site now, and I am about to write "not possible" or something similar, I now delete that, because I don't want to keep writing "Leonid will probably find a way" :) – tkott Mar 19 '12 at 14:40
  • @Sjoerd There may be cases when one need to automatically generate potentially many functions. Also, not having to name a function can be a big advantage, because you delay the funcion-creation from definition-time to run-time, which often adds flexibility. – Leonid Shifrin Mar 19 '12 at 17:48
  • It's not that difficult to create named functions on the fly. Can be done run-time. Unique is one option that I have seen you use quite a couple of times. Come to think about it, there's not that much difference between definition-time and run-time in MMA is it? – Sjoerd C. de Vries Mar 19 '12 at 20:25
  • @Sjoerd The difference is very simple: either you type your definitions and let them execute just once when you run the code cell, or you generate definitions at run-time yourself. While formally there is no difference between definition-time (which is also run-time), and what I mean by run-time, in practice there is. I have massively used run-time creation of function definitions, and that required custom assignment operators, which were basically saving local rules in some variable, so that I can produce global defintions from them on demand. Or, you can save chunks of held code. Either ... – Leonid Shifrin Mar 19 '12 at 22:56
  • @Sjoerd ...way, this requires modifications of the standard usage, particularly of operations like Set and SetDelayed. So, I agree that formally you are right - but to start routinely use this technique, convenience functions / libraries can help a lot. In other words - while pure functions (which are, in a way, generated at run-time, exactly where they are evaluated) are used by everyone, how many people routinely use run-time generation of pattern-based functions? The idea seems contrived to many, but it is no more so than that of a pure function. We just lack a convenient abstraction. – Leonid Shifrin Mar 19 '12 at 23:02
2

You can write a pure function whose application to an argument not matching the pattern you specified is returned unevaluated, using a trick with Defer and #0:

(If[MatchQ[_Integer][#1], #1 (#1 - 1), Evaluate[Defer][#0][#1]] &)[5]
(* 20 *)

(If[MatchQ[_Integer][#1], #1 (#1 - 1), Evaluate[Defer][#0][#1]] &)[x] (* (If[MatchQ[_Integer][#1], #1 (#1 - 1), Evaluate[Defer][#0][#1]] &)[x] *)

(If[MatchQ[_Integer][#1], #1 (#1 - 1), Evaluate[Defer][#0][#1]] &)[1.5 + 2.7] (* (If[MatchQ[_Integer][#1], #1 (#1 - 1), Evaluate[Defer][#0][#1]] &)[4.2] *)

FullForm[%] (* Defer[Function[If[MatchQ[Blank[Integer]][Slot[1]], Times[Slot[1], Plus[Slot[1], -1]], Evaluate[Defer][Slot[0][Slot[1]]]]][0.1`]] *)

As you can see, there is a head Defer (invisible in the standard form) that is automatically stripped if you edit or copy the output and use it as a new input. If you edit the argument to be an integer (as required by the pattern) and evaluate the expression, it will evaluate to an integer, otherwise it will return unevaluated again.


Alternatively, you can construct a pure function that explicitly wraps its application into Hold if it is to stay unevaluated. Or you can use HoldForm that has the same effect as Hold, but it is not displayed in the standard form (although, unlike Defer, it is not stripped automatically if the output is edited or copied). Both Hold and HoldForm can be explicitly unwrapped using ReleaseHold:

(If[MatchQ[_Integer][#1], #1 (#1 - 1), Hold[#0[#1]]] &)[x]
(* Hold[(If[MatchQ[_Integer][#1], #1 (#1 - 1), Hold[#0[#1]]] &)[x]] *)

ReleaseHold[%] (* evaluates to the same held result again *)

ReleaseHold[% /. x -> 5] (* substitute 5 as an argument before releasing hold ) ( 20 *)


Or, you can use Inactivate instead, whose effect can be reversed by Activate:

(If[MatchQ[_Integer][#1], #1 (#1 - 1), Inactivate[#0][#1]] &)[x]
(* The result is displayed in the standard form as

(If[MatchQ[_Integer][#1], #1 × (#1 + -1), Inactivate[#0][#1]] &)[x]

with inactive symbols tan-colored, which is actually

Inactive[Function][ Inactive[If][Inactive[MatchQ][_Integer][#1], Inactive[Times][#1, Inactive[Plus][#1, -1]], Inactive[Inactivate][#0][#1]]][x] *)

Activate[%] (* evaluates to the same inactive result *)

Activate[% /. x -> 5] (* substitute 5 as an argument before activating ) ( 20 *)

Vladimir Reshetnikov
  • 7,213
  • 27
  • 75
1

First make an Association between the Head of a your input and your input. The Keys of such Association will serve as the pattern:

#Integer (#Integer - 1) &@<|ToString@Head@# -> #|> & /@ {1, 2, 3}
Fortsaint
  • 2,060
  • 15
  • 17