# 1.1 Functions and Procedures

## 1.1.1 Felix functions

When you see code like this:

println$ "Square of " + str 1 + " is " + str (1 * 1); println$ "Square of " + str 2 + " is " + str (2 * 2); println$ "Sguare of " + str 3 + " is " + str (3 * 1);

Square of 1 is 1 Square of 2 is 4 Sguare of 3 is 3

You know you need a function (notice the typos on the last line?) Basic Felix functions are easy:

fun square(x:int)=>x * x; // define a function println$ "Square of " + str 1 + " is " + str (square 1); println$ "Square of " + str 2 + " is " + str 2.square; println$ "Sguare of " + str 3 + " is " + (str$ square 3);

Square of 1 is 1 Square of 2 is 4 Sguare of 3 is 9

We fixed the bug in the calculation of the square of 3, and
we're also showing the three ways to apply a function:
high precedence application using operator whitespace
which needs surrounding parentheses for correct grouping,
reverse application using operator dot, which is even higher
precedence than whitespace, and so does not, and finally we're
applying the `str`

function to a whitespace application
using operator dollar, which has lower precedence than whitespace.

There's a longer way to write a function:

fun long-winded-square(x:int):int = { val s = x * x; return x; }

This way allows complicated expressions to be broken up into arbitrary code.

Functions are not allowed to have side effects.

## 1.1.2 Felix Procedures

Still, there must be a way to repeat the print: there is, by using a procedure.

proc ps(x:int) { println$ "Square of " + str x + " is " + str x.square; } ps 1; ps 2; ps 3;

Square of 1 is 1 Square of 2 is 4 Square of 3 is 9

A procedure is like a function, except it returns no value, and it may and indeed should have side effects.

## 1.1.3 Multiple arguments

A function (or procedure) always has exactly one argument. However you can simulate multiple arguments with a tuple:

fun addup (x:int, y:int) => x + y; println$ addup (1,2); // 3 val pair = 1,2; println$ addup pair; // 3

3 3

The last line shows clearly that `addup`

takes a single argument
which is a pair (tuple with two components).

## 1.1.4 Function types

A function value has a type:

int -> int // type of square int -> void // type of ps int * int -> int // type of addup

## 1.1.5 Generators

There is a special kind of procedure that looks like a function and may have side-effects, it is called a generator:

var x =0; gen incx():int = { val tmp = x; ++x; return tmp; } println$ incx(), incx();

(0, 1)

When an expression contains one or more generator application, the applications
are lifted out and evaluated in pre-order: this is basically left to right
order of writing for terms at the same level, except that if a generator has
an argument that is, or contains a generator application, that will have to
be evaluated first. The serialisation of generator application is deterministic
and based on the structure of the expression being evaluated *after*
syntactic sugar is removed. For example

gen g1 (y:int) = { ++x; return y + x; } gen g2 (y:int) = { ++x; return y + 2 * x; } x = 0; var r1 = (g1 1).g2; println$ r1;

6

`r`

will be evaluated as:

x = 0; var a1 = g1 1; // 2 (x=1) var r2 = g2 a1; // 6 (x=2) println$ r2;

6

noting reverse application is just sugar for a swapped forward application.

Generators have the same type as a function. This is a design compromise in Felix.

## 1.1.6 C functions

The function and procedure:

cfun f(x:int) => x; cproc p(x:int) { println x; }

have types

int --> int int --> void

respectively, which are the types of classic C functions:

int (*)(int) void (*)(int)

You can use this kind of function to force generation of a classic C style function for performance, so you that know the type exactly, and so you can pass it as an argument to a C library. In particular such a function or procedure should not reference Felix globals (because this requires passing the thread frame pointer), nor do anything directly or indirectly requiring garbage collection (which also requires thread frame pointer since that in turn contains a pointer to the garbage collector).

C functions can be used wherever a Felix function is required, a wrapper is generated automatically.

C functions of this kind are still defined with Felix code: they're Felix functions with an enforced C interface. In fact many ordinary Felix functions will be reduced to C functions by the optimiser, but this form enforces the use of C interface.

It seems unfortunate that *whilst* a `cfun`

or `cproc`

has a C interface it
is defined in Felix, *whereas* a `cstruct`

is a Felix interface to a
struct defined in C, and `cenum`

and `cflag`

provide Felix models of enumerations
or sets of integer constants defined in C. The role reversal here seems confusing,
especially as Felix functions and types can be defined in C using `fun`

, `proc`

and `type`

keywords and C code given as a string, and `ctypes`

provides a shorthand form for
multiple instances of `type`

eliding the strings. In turn `cenum`

may be considered
a shorthand for a `type`

binding and a list of `const`

definitions. Also, a shorthand
for lifting C functions from libraries using a `fun`

or `proc`

without a
defining string can be used. The situation is further complicated by the
`callback`

feature.

# 1.2 Higher Order Functions

In Felix, functions can be nested:

fun f(x:int) = { fun g(y:long)=> x.long + y; return g; }

The function `f`

here has type {int -> (long -> long)}. This type is
the same as {int -> long -> long} since the arrow operator is right
associative. There's a simpler way to write the function `f`

:

fun f(x:int) (y:long) => x.long + y;

Here one says `f`

has arity 2. Note it still has only
one argument, namely `x`

of type `int`

. A function with arity
2 or greater is called a *higher order function*
or Hof for short.

Note that in:

proc h(x:int) (y:long) { println$ x.long + y; }

`h`

is a function, not a procedure: it has type

int -> (long -> void)

so that rather, `h`

is a function returning a procedure.

It is possible to partially apply a higher order function.

fun f2(x:int) (y:long) => x.long + y; val g = f2 1; println$ g 2l;

3

Here `g`

is just the value returned by `f`

when applied
to 1, which is a function accepting a `long`

and returning
a `long`

.

## 1.2.1 A style issue

Many functions of "two" arguments can be written either accepting a tuple of two components or as a higher order function of arity 2. Without optimisation, higher order functions are extremely inefficient: tuples are faster, but they cannot be partially applied. However, the higher order form does not permit the "arguments" to be "compressed" into a single value which the tuple form does.

However, Felix is pretty good at optimisation and both version of `f`

given above will likely reduce to a simple addition after inlining.

Therefore the question really is: are you most likely to aggregate the arguments, or the function with the first argument? Use a tuple in the first case and a higher order function in the second.

Of course, you should chose the form of a function which itself has the type required for it to be an argument of a higher order function such as an iteration, map or fold of some data structure.

The library module `categ`

defines a way to convert between these styles
for 2 or 3 "arguments". The function `curry`

takes a function accepting
a tuple of 2 or 3 components and makes it into a higher order function
with arity 2 or 3. The functions `uncurry2`

and `uncurry3`

reverse
this transformation and convert a higher order function of arity 2 or 3,
into a function accepting a tuple of 2 or 3 components, respectively.

## 1.2.2 Anonymous function values

You can write a function without a name in an expression:

val three = (fun (x:int)=> x + 1) 2;

There is a special short hand for procedures of unit argument:

val hello1 = { println "Hello"; };

This is an expression equivalent to

val hello2 = proc () { println "Hello"; };

There's a similar shorthand for function or unit argument:

val y = 1; val add1 = { val x = y + 1; return x; };

distinguished from the procedure case by ending with a return statement.