Lambda4J Homepage

The Functionals Library for Java

The functionals library adds some of the expressive power of functional programming to Java. This allows one to eliminate all loops from Java code and some conditional statements. With these artificial contructs gone, the code speaks of the problem, and to the solution, more clearly.

The project is currently developed in four areas:

The Lambda Functional Syntax Extensions to Java

Standard Lambda Calculus

The language extensions to Java allows one to create lambda terms in a way that closely resembles the lambda calculus. These extensions (with the underlying implementation in low-level Java code) give much of the strength of functional programming: particularly, functions are now first-class objects, and may be passed as parameters, assigned to variables, constructed, manipulated, transformed or delayed. For example:

final Function identity = \x . x; // equation 1
final Function add = \x . \y . x + y; // equation 2
final Function succ = add.apply(new Integer(1)); // equation 3

(see the documentation for the operations implemented into the lambda extensions)

create three functions. The first equation assigns a function that returns the value passed to it. The second equation assigns a function to the variable add that adds two numbers and returns the result as an object. The third equation curries the first argument of add to 1.

Note that there is no need for declaring types: the system infers the types from the body of the term. Also note that these extensions work only with objects: primitive types must be reified first to work in the system.

Functions are activated when arguments are applied to them. In the third equation above, the add functional object (also known as a functor or a functional) is "activated" by applying 1 to it. In this case, the activation returns a function. One could further activate add by applying a second argument: succ.apply(new Integer(7)) would return the Integer 8.

Function Construction Via Composition

The standard lambda calculus is expressive enough, in most cases, for creating functors. In some cases, however, there are pre-existing functors that one can use as building blocks to create new functors. Lambda4J provides syntactic extensions that allow one to manipulate functors to produce new functors. For example:

final Function succ = \'add(1); // equation 4
final Function oddNum = \' number /\ odd; // equation 5

(see the documentation for operations permitted for functional composition)

creates two functions: equation 4 creates succ again, this time using the currying operator, and equation 5 creates a predicate the returns true when its argument is both a number AND an odd one (the /\ operator is the set intersection operator -- a powerful logical-and operation (&&)).

Higher-Order Functions

Higher-order functions take a functor as at least one parameter to perform their task. Usually, these functions work with lists. The implemented higher-order functions can be grouped into the following areas: program transformation (map, fold, and unfold), selection (filter and partition), and inclusion (any and every). See the documentation for the signatures for these functions and what they do.

Lists Package

Object-oriented programming (covariance) focusses on the doing: independent objects interact by passing messages to each other, and a program is the sum of the messages. On the other hand, functional programming focusses on transforming (mapping) and reducing (folding): the emphasis here is that sole objects mean very little; it's the collection of objects that are transformed to give the program result.

This package, then, supplies the collection support for lambda4j in three areas: collection transformation, lazy lists and association lists.

Collection Transformation

Functionals work on lists, and work best on Lisp-like lists (meaning lists that have the same view from anywhere in the collection: the current element (the head or car) and the rest of the list (the tail or cdr)). Lazy lists provide that interface, and toList/1 provides a way to convert most anything that can be viewed as a collection into a functional list.

Lazy Lists

Lazy evaluation means that a computation is not performed until its value is actually needed. Most programming languages are eager by default (Haskell and its ilk being the notable exceptions). By introducing lazy computation to Java, particularly through the LazyList, one can express concepts (such as infinite lists) easily, while, at the same time, work with (compute) only what's needed.

There are several ways one can construct LazyList instances: one way, functionally, is to use unfold to generate a list from a seed value (as opposed to fold which computes a value from a list). Another way is to use (lazy) lists to create new lazy lists -- such as mapping values over a source list, or filtering a source list into target list(s).

Association Lists

The standard Java util package has a serious weakness: it does not provide support for multimaps -- maps that may have non-unique keys. The association list provides support for maps with keys both unique and non-unique. The system also facilitates mapping and folding transformations with syntax to obtain each tuple as a pair of values, e.g.:

\(key, val) . val;

would returns the list of values of an association list.

The Logical Framework

The logical framework is currently being actively developed and has a minimal set of functionality. The goal for this package is to flesh out the code for unification variables and predicates.

Unification variables are constrained and active variables: they can only be assigned if their constraints are met (e.g. if the logical variable 'A' has a constraint that it must be less than 100, A = 2250 will fail), and, once assigned, they retain that value unless explicitly released (transformed from a ground term to a free one).

They are also active in that the equation A - 3 = B + 7 shall be possible to write in Java (once the syntax is in the parser, that is), and the result of that equation shall be where both sides of the equation meet (where they unify). Further, X = Y, if neither has a value will unify the two free variables, so that a later (successful) Y = "Hi, there!" will also set X to that value, as well.

Predicates group tests and functions in a logical way, so that the state of a LogicalVariable determines what functional to apply. This grouping of functionals for dispatch is similar to multimethods from CLOS and Dylan, and very similar to the predicates of Prolog (except that they can be manipulated as functionals, so they more closely resemble the higher-order predicates found in the Mercury programming language). LogicalVariableTest contains use examples for predicates.

The project is under developement at the GNU Savannah website. Code, in its most current, feature-full, state is available there. In the meantime, one may obtain a tarball from the Cotillion Group, Inc. website.

Please read the files in the tarball for current (alpha) state and goals of this project.

You may contact me with questions and feature requests. I will give feature requests without implementation attached a lower priority.