diff --git a/doc/userdoc.org b/doc/userdoc.org
index 24bd03f3a93129837a209668696945cd7a3c8d08..e7fe896122d842402bad67c9118fdc22b4e9d8ee 100644
--- a/doc/userdoc.org
+++ b/doc/userdoc.org
@@ -2076,6 +2076,12 @@ or if ~(y1,...,ym)~ has already been defined in  ~Y1*...*Ym~
   (y1,...,ym) = f(x1,...,xn);
 #+END_SRC
 
+The ~pugs~ language handles two kinds of functions. User defined
+functions (see [[user-defined-functions]]) and builtin functions (see
+[[builtin-functions]]). They behave essentially the same and are both
+constant. In this context, it means that one cannot just declare or
+modify a function.
+
 *** Pure functions
 
 In the ~pugs~ language, functions are *pure functions* in the sense that
@@ -2084,18 +2090,196 @@ functions. They act as operators.
 
 #+BEGIN_note
 Actually these functions are not strictly /pure functions/ in the
-computer science context. The reason for that is that they can
+computer science sense. The reason for that is that they can
 eventually have side effects. A good example for that, is that it is
-possible to modify the random seed used by the code the code. In that
-case, the modified value is not a variable of the language itself but
-the internal random seed itself.
+possible to modify the random seed used by the code. In that case, the
+modified value is not a variable of the language itself but the
+internal random seed itself.
 #+END_note
 
 *** TODO Implicit type conversion for parameters and returned values
 
-*** TODO User-defined functions
+*** User-defined functions<<user-defined-functions>>
+
+To define user functions, the syntax mimics mathematics. The
+definition of the function itself is a *single* expression. This means
+that one cannot use ~if...else~, loops and there is not such keyword as
+~return~ in the ~C++~.
+
+The syntax of the definition of functions is
+#+BEGIN_SRC pugs :exports code
+  let f1 : X -> Y, x -> e;
+  let f2 : X -> Y1*...*Ym, x -> (e1,...,em);
+  let f3 : X1*...*Xn -> Y, (x1,...,xn) -> e;
+  let f4 : X1*...*Xn -> Y1*...*Ym, (x1,...,xn) -> (e1,...,em);
+#+END_SRC
+~X~, ~Y~, ~X1~, ..., ~Xn~ and ~Y1~, ..., ~Ym~ are /simple/ data types (not
+compound). The type of ~x~ is ~X~ and for lists, each argument ~xi~ belongs
+to ~Xi~. The function themselves are defined by the expressions ~e~ (or
+~e1~, ..., ~em~) which types are set by ~Y~ (or ~Y1~, ..., ~Ym~).
+
+
+Let us give a few examples.
+#+NAME: R-to-R-function
+#+BEGIN_SRC pugs :exports both :results output
+  let f: R -> R, x -> -x;
+
+  cout << "f(2.3) = " << f(2.3)
+       << "\nf(1) = " << f(1)
+       << "\nf(true) = " << f(true)
+       << "\n";
+#+END_SRC
+One observes the implicit conversion of the values passed by argument.
+#+results: R-to-R-function
+
+The following example illustrates the implicit conversion to the
+returned type
+#+NAME: R-to-R1-function
+#+BEGIN_SRC pugs :exports both :results output
+  let f: R -> R^1, x -> 2*x;
+
+  cout << "f(3.2) = " << f(2.3) << "\n";
+#+END_SRC
+One observes the implicit conversion of the values passed by argument.
+#+results: R-to-R1-function
+
+Using compound types as input and output, one can write
+#+NAME: R22-R-string-to-R-string-function
+#+BEGIN_SRC pugs :exports both :results output
+  let f : R^2x2*R*string -> R*string*R^3x3,
+          (A,x,s) -> (x*A[0,0]*A[1,1]-A[1,0],
+                      A+","+x+","+s,
+                      (A[0,0], A[0,1], 0,
+                       A[1,0], A[1,1], 0,
+                            0,      0, x));
+  let x : R, x=0;
+  let s : string, s= "";
+  let A : R^3x3, A = 0;
+  (x,s,A) = f((1,2,3,4), 2.3, "foo");
+  cout << "x = " << x
+       << "\ns = " << s
+       << "\nA = " << A << "\n";
+  let (y,t,A2):R*string*R^3x3, (y,t,A2) = f((3,1,4,2), -5.2, "bar");
+  cout << "y = " << y
+       << "\nt = " << t
+       << "\nA2 = " << A2 << "\n";
+#+END_SRC
+This meaningless example produces the following result.
+#+results: R22-R-string-to-R-string-function
+
+**** Lifetime of functions arguments
+
+The arguments used to define a function are *local* variables that
+exists only during the evaluation of the function.
+
+Let us consider the following example
+#+NAME: lifetime-of-function-args
+#+BEGIN_SRC pugs :exports both :results output
+  let a:R, a = 1.4;
+
+  let plus: R -> R, a -> (a>0)*a;
+
+  cout << "plus(1)    = " << plus(1) << "\n";
+  cout << "plus(-3.2) = " << plus(-3.2) << "\n";
+  cout << "a          = " << a << "\n";
+#+END_SRC
+This gives the expected result: the value of the variable ~a~ is
+unchanged.
+#+results: lifetime-of-function-args
+
+**** Non-arguments variables in function expressions
+
+Here we discuss rapidly of using variables (which are not arguments)
+in function expressions.
+
+#+NAME: non-arg-variables-in-functions
+#+BEGIN_SRC pugs :exports both :results output
+  let a:R, a = 1.4;
+
+  let plus: R -> R, x -> (x>0)*a;
+  cout << "a = " << a << "\n";
+  cout << "plus(2.2)    = " << plus(2.2) << "\n";
+  cout << "plus(-3.2) = " << plus(-3.2) << "\n";
+
+  a = 2;
+  cout << "a = " << a << "\n";
+  cout << "plus(2.2)    = " << plus(2.2) << "\n";
+  cout << "plus(-3.2) = " << plus(-3.2) << "\n";
+#+END_SRC
+While the function itself is a constant object, one sees that since
+the value of ~a~ is changed, the value function is implicitly
+modified. /This is a dangerous feature and should be avoid!/
+#+results: non-arg-variables-in-functions
+
+Since functions themselves are variables one can call functions in
+#+NAME: functions-in-functions
+#+BEGIN_SRC pugs :exports both :results output
+  let plus: R -> R, x -> (x>0)*x;
+  let minus: R -> R, x -> -(x<0)*x;
+
+  let pm : R -> R*R, x -> (plus(x), minus(x));
+  let toR2: R*R -> R^2, (x,y) -> (x,y);
+
+  cout << "pm(2) = " << toR2(pm(2)) << " pm(-3) = " << toR2(pm(-3)) << "\n";
+#+END_SRC
+One observes the utility function ~toR2~ that is used to perform the
+output since ~cout~ does not handle compound types output. One gets
+#+results: functions-in-functions
+
+**** Lifetime of user-defined functions
+
+Since functions are somehow variables, the lifetime of functions
+follows the similar rules.
+
+Let us give an example
+#+NAME: functions-lifetime
+#+BEGIN_SRC pugs :exports both :results output
+  let f: R -> R, x -> 2.3*x+2;
+  {
+    let f: R -> R, x -> 1.25*x+3;
+    cout << "block 1:  f(2) = " << f(2) << "\n";
+    {
+      let f: R -> R, x -> 3.25*x-0.3;
+      cout << "block 2:  f(2) = " << f(2) << "\n";
+    }
+  }
+  for (let i:N, i = 1; i<=2; ++i) {
+    let f: R -> R, x -> i*x+2;
+    cout << "for(i=" << i << "): f(2) = " << f(2) << "\n";
+  }
+  cout << "global:   f(2) = " << f(2) << "\n";
+#+END_SRC
+Running this example produces
+#+results: functions-lifetime
+
+**** Recursion
+
+Since functions cannot be simply declared but must be defined, double
+recursion is not possible. Thus, there is no equivalent construction
+in ~pugs~ of the following ~C++~ code
+#+BEGIN_SRC C++ :exports source
+  int f(int i);
+  int g(int i)
+  {
+    if (i < 0)
+      return 0;
+    else
+      return f(i-1);
+  }
+
+  int f(int i) { return g(i); }
+#+END_SRC
+Moreover simple recursion if forbidden for similar reasons, since
+functions are made of a single expression (one cannot use statements),
+there would be no way to end the recursion. Thus, the code
+#+NAME: no-recursion
+#+BEGIN_SRC pugs-error :exports both :results output
+  let f: N->N, n -> f(2*n);
+#+END_SRC
+produces the following compilation time error
+#+results: no-recursion
 
-*** TODO Builtin functions
+*** TODO Builtin functions<<builtin-functions>>
 
 ** TODO modules