install

tutorials

- Java API

- Java + LISP

- Lisp Repl

- Assembler

Javadoc

Lisp manual

fun4j - functional programming for the JVM

Looking for a better notation for functions

As we have seen in the tutorial on the fun4j Java API Java has no native support for defining functions. Defining functions as anonymous classes is currently the most advanced thing Java has to offer here. But this solution is not always easy to read and involves a lot of boilerplate coding. In particular for simple functions the boilerplate overhead is quite high and takes out most of the fun.

The fun4j way of defining functions in a concise way is to use lambda-terms in classic LISP syntax. Just compare the following definitions:

// the Java way to define a function
Function pow2 = new Function(){
    @Override
    public Object apply(Object... args) {
        return (Integer)args[0] * (Integer)args[0];
    }
};

This is the typical Functions as anonymous class approach, that we used through the Java API tutorial.

Function pow2 = fn("(lambda (n) (* n n))");

This is the fun4j way. If you know LISP or Scheme or some other functional language this definition does not need much explanation. But if you don't, you'll learn it quickly.

LISP ? Yes, LISP !

"Lisp's core occupies some kind of local optimum
in the space of programming languages."
- John McCarthy, inventor of LISP

There are a few reasons why I choose LISP:

For an introduction to lambda-calculus and LISP please refer to the following links: LISP article on Wikipedia
Lambda calculus

Some more examples

The next code snippet shows a new application for foldright: here fold right is used to compute the product of the integers from 1 to 10. The result of this computation is crosschecked against a computation of factorial(10), which is again the product from 1 to 10:

import static org.fun4j.Template.fun4j;
import static org.fun4j.Template.fn;
 
Collection<Integer> col = fun4j.asCollection(1 , 2, 3, 4, 5, 6, 7, 8, 9, 10);
Function mul = fn("(lambda (x y) (* x y))");

// define factorial function
fun4j.eval("(define fac (lambda (n) (if (= n 0) 1 (* n (fac (sub1 n))))))");

actual = (Integer) fun4j.foldright(mul, 1, col));
Integer expected = (Integer) fun4j.eval("(fac 10)");

assertEquals(expected, actual);     

In this example all functions are defined in lisp syntax. mul is a signed with an anonymous function. fac is defined (with the special define) as a named function in the fun4j runtime environment. Thus it can be accessed later in the call to fun4j.eval("(fac 10)");

The interesting story here is that the Lisp expression are internally compiled into standard Java classes implementing the org.fun4j.Function Interface. That is the structure of Lisp function calls has been mapped to the Java Object + method calls as provided by the JVM. Thus the Lisp definitions are completely interoperable with ordinary Java code. This makes it easy to integrate Lisp code with existing Java code. You'll find a lot of other examples of how Lisp functions are used in Java Code in the fun4j junit testcases.

But how does it work ?

The compiler wraps a Function object only around the outmost Lisp expression. Thus it's possible to write fairly complex LISP code that runs within one Java method without wasting stack space for allocating objects. The compiler also provides a simple Tail Call Optimization that eliminates recursive method invocations wherever possible. If you want to know how this works, have a look at the source-code of the method org.fun4j.compiler.Compiler.compile(...)

If you want to learn about the inner workings of fun4j have a look the tutorial on the functional assembler which forms the base of fun4j.

Don't call us, we'll call you !

Due to this direct interoperability of Java and Lisp code in fun4j it is not only possible to evaluate Lisp code from within your Java applications but also to call Java from Lisp code. In the following example a Lisp function is defined based on a Java defined Function class.

fun4j.eval("(define hash (javafunction 'org.fun4j.functions.Hash))");
System.out.println(fun4j.eval("(hash 'just-a-symbol)"));

You can also call static methods from Lisp code, as shown in the next snippet:

fun4j.eval("(define getproperties (lambda () (staticfunction 'java.lang.System 'getProperties "()Ljava/util/Properties;" )))");  
System.out.println(fun4j.eval("(getproperties )"));

It's also possible to access Java methods dynamically from fun4j Lisp code with the Dot operator:

System.out.println(fun4j.eval("(. 'System 'getProperties)"));

Accessing Java Objects with the Dot operator

As shown in the previous example the Dot operator allow to call static methods of any Java class. But it can do much more, as shown in the following pseudo code:

(. Classname-symbol member-symbol)
(. Classname-symbol method-symbol args*)

(. instance-expr member-symbol)
(. instance-expr method-symbol args*)

The Dot ('.') operator is a generic access operator to Java objects and classes. It can access both methods and fields.

If the first operand is a symbol that resolves to a class name, the access is considered to be to a static member of the named class. Otherwise it is assumed to be an instance member and the first argument is evaluated to produce the target object.

If the second operand is a symbol and no arguments are supplied it is taken to be a field access: the name of the field is the name of the symbol, and the value of the expression is the value of the field, unless there is a no argument public method of the same name, in which case it resolves to a call to the method.

Here are some examples:

System.out.println(fun4j.eval("(. 'Math 'PI)"));       
System.out.println(fun4j.eval("(. 'Math 'random )")); 
System.out.println(fun4j.eval("(. [1 2 3 4] 'size)"));        

The first line accesses the static field PI of the class java.lang.Math. The second line calls the static method random() of class java.lang.Math. The third line parses a Vector [1, 2, 3, 4] and calls the size method.

An here are some more advanced examples from the testsuite:

Box box0 = new Box(0.0,0.0,10.0,10.0);
fun4j.eval("(. box0 'contains 5.0 6.0)"));

A Box instance box0 is created. The Dot operator is then called to invoke the method contains with two arguments.

Box box1 = new Box(0.0,0.0,5.0,5.0);
Box box2 = new Box(0.0,0.0,9.0,9.0);
Collection <Box> col = fun4j.asCollection(box0, box1, box2);
Function getSize = fn("(lambda (box) (. box 'getSize))");
Collection<?> result = fun4j.map(getSize, col);

And in this snippet two more boxes are created and a collection col is built containing the the box instances. Next a function getSize is defined that takes a Box instance as input parameter and return the the result of invoking the Box.getSize() method on the instance. Finally fun4j.map is used to compute the size of all boxes and return them as a collection.