OCaml Tutorial: Function

,

This page gives a practical understanding of functions in Ocaml.

Function With 1 Parameter

To define a function, use the form function ‹parameter name› = ‹expression›.

(* a function that returns its argument + 1 *)
function n -> n + 1 ;;

(* applying the function to the value 2 *)
(function n -> n + 1) 2;;   (* ⇒ 3 *)

Function With n Parameters

To define a function with 2 parameters, you do it by defining a function with 1 parameter, that returns another function of 1 parameter. The form is this:

function ‹parameter› -> function ‹parameter› -> ‹expression›

The following is a example:

(* defining a function “f(x,y)” that computes x + y *)
function x -> ( function y -> x + y );;

(* applying the function to values *)
(function x -> ( function y -> x + y) ) 3 4;; (* ⇒ 7 *)

In the above example, the line function x -> ( function y -> x + y ), means a function with parameter x, which returns function y -> x + y, which is a function with parameter y, and computes x + y.

The number of parameters of a function is called its “arity”. So, a function with 2 arguments would be a function with arity 2.

To define a function with 3 or more parameters, the same pattern is used.

function ‹parameter 1› ->
 function ‹parameter 2› ->
  function ‹parameter 3› ->
   …
    -> ‹expression›

At the language core, all multi-parameter functions are decomposed into a sequence of functions of 1 parameter.

There is a syntax shortcut for defining functions of multiple parameters. The form is:

fun ‹parameter 1› ‹parameter 2› ‹parameter 3› … -> ‹expression›

Example:

fun x y -> x + y;;

(fun x y -> x + y) 3 4;;                (* ⇒ 7 *)

This is the more practical way to define a function.

Assign A Name To Function

A function can be assigned to a variable, thus giving it a name.

let sumOfTwo = fun x y -> x + y;;              (* giving function a name *)
sumOfTwo 3 4;;                                 (* ⇒ 7 *)

Syntax Shortcut For Defining A Function

The form let ‹name› = fun ‹params› -> ‹expr› is used often, so that there is a shortcut. The shortcut form is:

let ‹function name› ‹param1› ‹param2› … = ‹expression›

Example:

(* the following are all equivalent *)
let sumOfTwo = function x -> function y -> x + y;;
let sumOfTwo = fun x y -> x + y;;
let sumOfTwo x y = x + y;;
sumOfTwo 3 4;;                          (* ⇒ 7 *)

Operator Precedence For Functions

The operator for function definition -> is more sticky to the right. This means, when you have ‹stuff1› -> ‹stuff2› -> ‹stuff3›, ocaml will interpret it as ‹stuff1› -> ( ‹stuff2› -> ‹stuff3› ). This means when you define a function that returns a function, you don't have to use parenthesis.

However, function application in ocaml favors the left side. If you write f g h x;;, ocaml will interpret it as ((f g) h) x;;. This is particular important to know when you use functions of multiple arguments. Here's some examples:

let f s = s ^ "1";;                     (* append 1 to a string *)
let g s = s ^ "2";;                     (* append 2 to a string *)
let h s = s ^ "3";;                     (* append 3 to a string *)

h (g (f "x"));;                         (* ⇒ "x123" *)

In the above, if you use f g h "x";;, the compiler will give a error:

# Characters 0-1:
  f g h "x";;
  ^
Error: This function is applied to too many arguments,
maybe you forgot a `;'

Because it starts by computing f(g). This results in a error right away, because by your definition, f has one parameter of type string, and returns a string, but you are trying to apply the result to h "x".

If you call ((f g) h) "x", then the error is more clear:

  ((f g) h) "x";;
      ^
Error: This expression has type string -> string but is here used with type
         string

The error says “but is here used with type string” because your function g is defined to be of type “string → string”, and you are feeding g to f, which expect a string.

Using Operator As Function

Operators, such as “+ *” etc, can be considered as functions of 2 parameters. They can be used as a function in ocaml. A function call has the form “f arg1 arg2”, while operator such as “+” is used in the form “arg1 + arg2”. Sometimes it is useful to call operators in the function form, so that the power of function and its syntax fully apply to all operators.

To use operator in the form of a function, the operator must be bracketed with paren. The form is:

(‹operator symbol›) ‹arg1› ‹arg2›

Example:

( + ) 3 4;;                             (* ⇒ 7 *)
( *. ) 23. 3.;;                         (* ⇒ 69. *)
( + ) ((+) 3 4) 5;;                       (* ⇒ 12 *)
( * ) ((+) 3 4) 5;;                       (* ⇒ 35 *)

Note that extra paren for grouping is necessary.

Defining Your Own Operator

You can define your own operator. The form is:

let ( ‹symbol chars› ) ‹left arg› ‹right arg› = ‹expression›

Example:

(* define operator for vector addition of 2 dimensional vectors *)
(* using 2-tuple as vectors *)
let ( @+ ) vec1 vec2 = ( (fst vec1)+(fst vec2), (snd vec1)+(snd vec2) ) ;;
(3,4) @+ (5,6);;                        (* ⇒ (8,10) *)

Note: the char sequence used for operator is limited to symbol chars, such as “! @ # $ % ^ & *”. They cannot letters, numbers, nor Unicode char.

Recursive Function

Functions that are defined by referring to itself, must be declared with “rec”.

(* example of factorial function *)
let rec f n = if n == 1 then 1 else n * f (n-1);;
f 3                                     (* ⇒ 6 *)

(* example of fibonacci sequence. *)
(* nth term is sum of previous 2 terms. Starting with 0 and 1. *)
let rec f n = match n with 0 -> 0 | 1 -> 1 | x -> f (n-1) + f (n-2);;
f 9;;                                  (* ⇒ 34 *)

Note: above recursive definitions are for example only. They are very inefficient.

blog comments powered by Disqus