6.17 Anonymous Functions

An anonymous function is a function that is function:anonymous defined anonymous function by giving a list of parameters, the maps-to compound +-> @+-> symbol +-> (from the mathematical symbol ↦), and by an expression involving the parameters, the evaluation of which determines the return value of the function.

( parm1, parm2, ..., parmN ) +-> expression

You can apply an anonymous function in several ways.

  1. Place the anonymous function definition in parentheses directly followed by a list of arguments.
  2. Assign the anonymous function to a variable and then use the variable name when you would normally use a function name.
  3. Use == to use the anonymous function definition as the arguments and body of a regular function definition.
  4. Have a named function contain a declared anonymous function and use the result returned by the named function.

6.17.1 Some Examples

Anonymous functions are particularly useful for defining functions on the fly. That is, they are handy for simple functions that are used only in one place. In the following examples, we show how to write some simple anonymous functions.

This is a simple absolute value function.

x +-> if x < 0 then -x else x
\[\]
x↦ifx<0then-xelsex

Type: AnonymousFunction

abs1 := %
\[\]
x↦ifx<0then-xelsex

Type: AnonymousFunction

This function returns true if the absolute value of the first argument is greater than the absolute value of the second, false otherwise.

(x,y) +-> abs1(x) > abs1(y)
\[\]
(x,y)↦abs1(y)<abs1(x)

Type: AnonymousFunction

We use the above function to sort a list of integers.

sort(%,[3,9,-4,10,-3,-1,-9,5])
\[\]
[10,-9,9,5,-4,-3,3,-1]

Type: List Integer

This function returns 1 if i+j is even, -1 otherwise.

ev := ( (i,j) +-> if even?(i+j) then 1 else -1)
\[\]
 

Type: AnonymousFunction

We create a four-by-four matrix containing 1 or -1 depending on whether the row plus the column index is even or not.

matrix([ [ev(row,col) for row in 1..4] for col in 1..4])
\[\]
[1-11-1-11-111-11-1-11-11]

Type: Matrix Integer

This function returns true if a polynomial in x has multiple roots, false otherwise. It is defined and applied in the same expression.

( p +-> not one?(gcd(p,D(p,x))) )(x^2+4*x+4)
\[\]
true

Type: Boolean

This and the next expression are equivalent.

g(x,y,z) == cos(x + sin(y + tan(z)))

Type: Void

The one you use is a matter of taste.

g == (x,y,z) +-> cos(x + sin(y + tan(z)))
1 old definition(s) deleted for function or rule g

Type: Void

6.17.2 Declaring Anonymous Functions

If you declare any of the arguments you must declare all of them. Thus,

(x: INT,y): FRAC INT +-> (x + 2*y)/(y - 1)

is not legal.

This is an example of a fully declared anonymous function. function:declaring function:anonymous:declaring The output shown just indicates that the object you created is a particular kind of map, that is, function.

(x: INT,y: INT): FRAC INT +-> (x + 2*y)/(y - 1)
\[\]
theMap(...)

Type: ((Integer,Integer) -> Fraction Integer)

FriCAS allows you to declare the arguments and not declare the return type.

(x: INT,y: INT) +-> (x + 2*y)/(y - 1)
\[\]
theMap(...)

Type: ((Integer,Integer) -> Fraction Integer)

The return type is computed from the types of the arguments and the body of the function. You cannot declare the return type if you do not declare the arguments. Therefore,

(x,y): FRAC INT +-> (x + 2*y)/(y - 1)

is not legal. This and the next expression are equivalent.

h(x: INT,y: INT): FRAC INT == (x + 2*y)/(y - 1)
Function declaration h : (Integer,Integer) -> Fraction Integer
   has been added to workspace.

Type: Void

The one you use is a matter of taste.

h == (x: INT,y: INT): FRAC INT +-> (x + 2*y)/(y - 1)
Function declaration h : (Integer,Integer) -> Fraction Integer
   has been added to workspace.
1 old definition(s) deleted for function or rule h

Type: Void

When should you declare an anonymous function?

  1. If you use an anonymous function and FriCAS can’t figure out what you are trying to do, declare the function.
  2. If the function has nontrivial argument types or a nontrivial return type that FriCAS may be able to determine eventually, but you are not willing to wait that long, declare the function.
  3. If the function will only be used for arguments of specific types and it is not too much trouble to declare the function, do so.
  4. If you are using the anonymous function as an argument to another function (such as map or sort), consider declaring the function.
  5. If you define an anonymous function inside a named function, you must declare the anonymous function.

This is an example of a named function for integers that returns a function.

addx x == ((y: Integer): Integer +-> x + y)

Type: Void

We define g to be a function that adds 10 to its argument.

g := addx 10
Compiling function addx with type
  PositiveInteger -> (Integer -> Integer)
\[\]
theMap(...)

Type: (Integer -> Integer)

Try it out.

g 3
\[\]
13

Type: PositiveInteger

g(-4)
\[\]
6

Type: PositiveInteger

function:anonymous:restrictions An anonymous function cannot be recursive: since it does not have a name, you cannot even call it within itself! If you place an anonymous function inside a named function, the anonymous function must be declared.