I thought that I remembered a way to write a function definition using "|", but can't find documentation for it. So for example, I'd want to define:

f[1, x_] := x^2;
f[2, x_] := x*12;

I thought there was a syntax, kind of like a "select case" or "switch" statement that used "|". Is there?

  • 1
    $\begingroup$ Are you thinking of Condition? (look it up in the docs) $\endgroup$ – Szabolcs Mar 15 '14 at 14:00
  • $\begingroup$ In this particular case, it does not seem appropriate to use such a construct anyway, because your r.h.sides are different. But also in general, the use of Alternatives in the top-level function definitions is not allowed. $\endgroup$ – Leonid Shifrin Mar 15 '14 at 14:01
  • $\begingroup$ @LeonidShifrin Just to clarify, f[1, x_] | f[3, x_] := x^2 is not allowed, but f[1 | 3, x_] := x^2 is allowed. (It's not clear to me which the OP is trying to recall, if either.) $\endgroup$ – Michael E2 Mar 15 '14 at 14:23
  • $\begingroup$ @MichaelE2 I meant the first one, that's why I said "top-level". I agree that I could've made that more clear. $\endgroup$ – Leonid Shifrin Mar 15 '14 at 14:37
  • $\begingroup$ @LeonidShifrin I figured that out, but I was thinking of the second one when I read the question. I really was trying to clarify it for the OP, just in case. $\endgroup$ – Michael E2 Mar 15 '14 at 14:39

It sounds like you are describing pattern guards or pattern-matching syntax found variously in ML/SML/OCAML/Haskell/F#. For example, in Haskell one could write:

-- This is Haskell, *not* Mathematica

f a x
    | a == 1 = x ^ 2
    | a == 2 = x * 12

Mathematica does not support this kind of syntax using a pipe symbol. The definitions exhibited in the question are idiomatic. We can write code that looks vaguely like the Haskell syntax using explicit pattern matching:

f[a_, x_] := a /.
    { 1 :> x ^ 2
    , 2 :> x * 12
    , _ :> $Failed

This is not very idiomatic. It could possibly be convenient for more elaborate argument list shapes and conditions. The $Failed case was added to point out that we would otherwise have the (surprising?) behaviour of returning a unchanged if it is not 1 or 2. An Message / Abort sequence might be more appropriate, depending upon the application (and mimicking Haskell's built-in behaviour).

Other answers to this question show how one can avoid repeating argument lists across function definitions using features such as Switch or Alternatives.

| improve this answer | |

You may be remembering a way that I sometimes write function definitions or replacement rules using what I call vanishing patterns, using Alternatives (short form |). Some examples:

This technique can considerably condense some code, but at the expense of clarity for those not familiar with it, and often a slight decrease in performance. I do not see any (simple) way to apply it to the example in the question, and shoehorning the method into code where it does not naturally fit (for one accustomed to it) surely hurts clarity and should be avoided outside of "code golf" games.

To provide a simple example of the method where I believe it does fit consider:

f[a_Real, x_] := x*a
f[b_Integer, x_] := x^b

This could instead be written:

f[a_Real | b_Integer, x_] := (x*a)^b

Whichever pattern (a_Real or b_Integer) does not match is left out of the right-hand-side, and because of the single-argument behavior of Times and Power this is handled correctly.

Another place the method works very well is inserting elements into an expression at specific places based on pattern. For example, suppose you want an function than takes a list and an integer, and appends the integer if it is odd and "prepends" the integer if it is even. This can be written cleanly as:

 g[{x___}, e_?EvenQ | o_?OddQ] := {e, x, o}


Fold[g, {}, Range@10]
{10, 8, 6, 4, 2, 1, 3, 5, 7, 9}

More simply you can use Alternatives to match different input forms, e.g.:

| improve this answer | |

There is a Switch statement, but the syntax to do what you need is

f[s_,x_]:= Switch[s,
    1, x^2,
    2, x*12,
    True, "something else"

The third option *which I forgot in my first edit) takes care of what happens when s is neither 1 or 2.

Otherwise you could use the functional overloading approach you mentioned in your question. It works because Mathematica will order your definitions from the more specific to the more general, and after defining f[1,x_] and f[2,x_] you can add a definition for the general case f[s_,x_]. I like this approach better, since it can leave the result unevaluated when x is not 1 or 2.

The 'pipe' (i.e. Alternatives) can be used to assign values that are the same for a finite set of a certain parameter's values, like in

g[1 | 2, x_] := x^("1 or 2")
g[y_,x_]:=x^"something else"

It means that the function have the same output for alternative values of input.

| improve this answer | |

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.