Next

Prev

Prev-tail

Tail

Up

Chapter 10
Functional Programming

urbiscript support functional programming through first class functions and lambda expressions.

 10.1 First class functions
 10.2 Lambda functions
 10.3 Lazy arguments

10.1 First class functions

urbiscript has first class functions, i.e., functions are regular values, just like integers or strings. They can be stored in variables, passed as arguments to other functions, and so forth. For instance, you don’t need to write function object.f(){/* ... */} to insert a function in an object, you can simply use setSlot.

 
var o = Object.clone | {}; 
// Here we can use f as any regular value
 
o.setSlot(
"m1"
, function () { echo(
"Hello"
) }) | {}; 
// This is strictly equivalent
 
var o.m2 = function () { echo(
"Hello"
) } | {}; 
o.m1; 
[00000000] *** Hello
 
o.m2; 
[00000000] *** Hello

This enables to write powerful pieces of code, like functions that take function as argument. For instance, consider the all function: given a list and a function, it applies the function to each element of the list, and returns whether all calls returned true. This enables to check very simply if all elements in a list verify a predicate.

 
function all(list, predicate) 
{ 
  for (var elt : list) 
    if (!predicate(elt)) 
      return false; 
  return true; 
} | {}; 
// Check if all elements in a list are positive.
 
function positive(x) { x >= 0 } | {}; 
all([1, 2, 3], getSlot(
"positive"
)); 
[00000000] true
 
all([1, 2, -3], getSlot(
"positive"
)); 
[00000000] false

It turns out that all already exists: instead of all(list, predicate), use list.all(predicate), see List (??sec:std-List).

10.2 Lambda functions

Another nice feature is the ability to write lambda functions, which are anonymous functions. You can create a functional value as an expression, without naming it, with the syntax shown below.

 
// Create an anonymous function
 
function (x) {x + 1} | {}; 
// This enable to easily pass function
 
// to our "all" function:
 
[1, 2, 3].all(function (x) { x > 0}); 
[00000000] true

In fact, the function construct we saw earlier is only a shorthand for a variable assignment.

 
// This ... 
function obj.f (/*...*/) {/*...*/}; 
// ... is actually a shorthand for this 
var obj.f = function (/*...*/) {/* ... */};

10.3 Lazy arguments

Most popular programming languages use strict arguments evaluation: arguments are evaluated before functions are called. Other languages use lazy evaluation: argument are evaluated by the function only when needed. In urbiscript, evaluation is strict by default, but you can ask a function not to evaluate its arguments, and do it by hand. This works by not specifying formal arguments. The function is provided with a call object that enables you to evaluate arguments.

 
// Note the lack of formal arguments specification
 
function first 
{ 
  
// Evaluate only the first argument.
 
  call.evalArgAt(0); 
} | {}; 
first(echo(
"first"
), echo(
"second"
)); 
[00000000] *** first
 
function reverse 
{ 
  call.evalArgAt(1); 
  call.evalArgAt(0); 
} | {}; 
reverse(echo(
"first"
), echo(
"second"
)); 
[00000000] *** second
 
[00000000] *** first

A good example are logic operators. Although C ++ is a strict language, it uses a few logic operators. For instance, the logical and (&&) does not evaluate its right operand if the left operand is false (the result will be false anyway).

urbiscript logic operator mimic this behavior. The listing below shows how one can implement such a behavior.

 
function myAnd 
{ 
  if (call.evalArgAt(0)) 
    call.evalArgAt(1) 
  else 
    false; 
}|; 
 
function f() 
{ 
  echo(
"f executed"
); 
  return true; 
}|; 
 
myAnd(false, f()); 
[00000000] false
 
 
myAnd(true, f()); 
[00000000] *** f executed
 
[00000000] true