In a nutshell, you write a lambda expression, such as
(fun x -> x end fun y -> y end)in a file, say my.lambda. You give it to the compiler (of course written in Java)
% java -jar lambda2java.jar my.lambdaand you'll get a Java program my.java, which you can then compile and run:
% javac my.java % java my
new Lambda() { Lambda apply(Lambda x) { return <c>; } }where Lambda is an abstract class that makes sure that every lambda expression knows how to handle apply.
The idea of using anonymous inner classes in Java as target for compiling lambda expressions is also present in Matthew Might's Scheme-to-Java compiler.
Plotkin showed in "Call-by-name, call-by-value and the lambda-calculus" (TCS 1 (1975), 125-159) that this machine faithfully implements a restricted form of the lambda calculus called λv. Thanks to Matthias Felleisen for pointing out the relevance of this paper for this work.
More specifically, the reduction implemented by the translation and the JVM reduces only closed expressions, and repeatedly reduces the left-most inner-most redex outside lambda-abstractions.
fun f -> fun x -> (f (f x)) end endthen the translated Java program will print the number 2.
As a more elaborate example, here is how to raise the number 3 to the power of 4 in the lambda calculus.
( (fun i -> fun j -> (i j) end end fun f -> fun x -> (f (f (f (f x)))) end end ) fun f -> fun x -> (f (f (f x))) end end )The Java program resulting from compiling this lambda expression will print 81, when compiled and run.
Now you can run the compiler, and compile and run the result:
% java -jar lambda2java.jar power.lambda % javac power.java % java power 81If you want to play with the compiler, feel free to download the Java sources from lambda2java.zip.
However, any lambda expression can be compiled and run. It's just that the result of the evaluation will not be displayed except in terms of Church numerals.
Another restriction is of course that the Java compiler only accepts the results of compiling closed lambda expressions. Lambda expressions with free variables can be compiled to Java, but the resulting Java programs have these variables undefined, and thus cannot themselves be compiled.
abstract class Lambda { // every Lambda has an apply function // (to say what it should return, when applied) abstract Lambda apply(Lambda x); // to demonstrate that this all works, // we add functions as_church_numeral and to_int // as_church_numeral inteprets _this_ // as a church numeral by applying // it to Inc and Zero int as_church_numeral() { return this.apply(new Inc()).apply(new Zero()).to_int(); } // non-church-numerals should // be spotted as negative numbers int to_int() { return -1000000; }; } // Applying an Inc returns a lambda // expression whose to_int adds 1 to // the to_int-result of its argument class Inc extends Lambda { Lambda apply(final Lambda x) { return new Lambda() { Lambda apply(Lambda x) { return x; } public int to_int() { return x.to_int() + 1; } }; } } // a Zero is a lambda expression // whose to_int returns 0 class Zero extends Lambda { Lambda apply(Lambda x) { return x; } public int to_int() { return 0; } }The classes above are included in the result of the compilation, to make it self-contained. They are followed by the class that bears the name of your file that contains the lambda expression (in our case power). Here is how it looks, in that case. Note that the result of translating the lambda expression (the part new Lambda() {...}.apply(...) is converted to an integer using as_church_numeral(), and then printed.
class power { public static void main(String[] args) { System.out.println( new Lambda() { Lambda apply(final Lambda i) { return new Lambda() { Lambda apply(final Lambda j) { return i .apply( j ) ; } } ; } } .apply( new Lambda() { Lambda apply(final Lambda f) { return new Lambda() { Lambda apply(final Lambda x) { return f .apply( f .apply( f .apply( f .apply( x ) ) ) ) ; } } ; } } ) .apply( new Lambda() { Lambda apply(final Lambda f) { return new Lambda() { Lambda apply(final Lambda x) { return f .apply( f .apply( f .apply( x ) ) ) ; } } ; } } ) .as_church_numeral() ); } }