3.2. Defining Procedures

Felix supports three syntactic forms for definining procedures. The simplest form is illustrated by:
  proc f[t] (x:t, y:int) { print y; h x; }
You will note this function is polymorphic with one type argument t, it accepts a single argument of tuple type t * int.

This form supports an extension to curry form:

  proc f[t] (x:t) (y:int)
  {
    print y; h x;
  }
which is short hand for
  fun f[t] (x:t): t -> (int -> void) =
  {
    proc g(y:int) =
    {
      print y; h x;
    }
    return g;
  }
Procedures also support lambda abstraction:
  (proc (x:int, y:int) { print y; h x; }) (1,2);
A special form can be used for procedures with unit argument:
  { print "Hello"; endl; }
is a procedure with unit argument, and is short hand for:
  (proc(){print "Hello"; endl; })
You should note very carefully the following are NOT equivalent:
  proc f(){ print "Hello"; endl; }
  val f = { print "Hello"; endl; }
The first line defines a procedure f, but does not form a closure. The second line stores a closure of an anonymous procedure into value f. Although any application of either f is equivalent, the lookup rules for variable and function names are distinct. Procedure names can be overloaded, and lookup choses the right procedure to use in an application based on the procedure argument.

Variable names, even if used applicatively, are never overloaded and do not participate in overload resolution.

Felix also allows procedures to provide pre-conditions. Here is an example:

  proc f(x: int, y:int when x+y>0)
  {
    print (x + y); endl;
  }