TotallyLazy

A complete functional environment for Java

Fork me on GitHub

Motivation

TotallyLazy brings functional programming techniques to Java in a way that complements the standard library while adding missing features like persistent data structures, parser combinators and more. TotallyLazy has been built by usage so has hundreds of helper functions and always stives for the highest level of interop with standard Java interfaces.

Features

The following are some of the features in TotallyLazy

The sequence class allows you to build up a computation out of smaller operations. It's very similar to Java 8 Streams but has hundreds more methods and uses explicit parallelism (which tends to be better for IO operations). It has methods from Clojure, Scala, Haskell and F#.

Bring in some static imports:

import static com.googlecode.totallylazy.Sequences.*; // Where the sequence factory methods live;
import static com.googlecode.totallylazy.Callables.*; // Lots of helper functions;
import static com.googlecode.totallylazy.numbers.Numbers.*; // Used for working with Numbers

Now we can try some of the following:

sequence(1, 2, 3, 4).filter(even); // lazily returns 2,4
sequence(1, 2).map(toString); // lazily returns "1", "2"
sequence(1, 2).mapConcurrently(toString); // lazily distributes the work to background threads
sequence(1, 2, 3).take(2); // lazily returns 1,2
sequence(1, 2, 3).drop(2); // lazily returns 3
sequence(1, 2, 3).tail(); // lazily returns 2,3
sequence(1, 2, 3).head(); // eagerly returns 1
sequence(1, 2, 3).reduce(sum); // eagerly return 6
sequence(1, 3, 5).find(even); // eagerly returns none()
sequence(1, 2, 3).contains(2); // eagerly returns true
sequence(1, 2, 3).exists(even); // eagerly return true
sequence(1, 2, 3).forAll(odd); // eagerly returns false;
sequence(1, 2, 3).fold(0, sum); // eagerly returns 6
sequence(1, 2, 3).toString(":"); // eagerly returns "1:2:3"

100+ more methods...

Option is very similar to Java 8 Optional class with a few more methods. The biggest difference is that Option is iterable (and monadic) so can be use in many more places than the Optional class

Bring in some static imports:

import static com.googlecode.totallylazy.Option.*; // Where the option factory methods live;
import static com.googlecode.totallylazy.numbers.Numbers.*; // Used for working with Numbers

Now we can try some of the following:

option(1); // returns some(1)
option(null); // returns none()
some(null); // Throws IllegalArgumentException
some(1).isDefined(); // returns true
none().isEmpty(); // returns true
some(3).filter(even); // returns none()
some(2).fold(1, sum); // returns 3
some("1").map(Integer::parserInt); // returns some(1)
for (T value : option(...)) System.out.print(value); // Only prints the value if it's defined

There is no equivalent in Java 8 but this will be familar for Haskell or Scala progammers. Either's represent a single value that is either the right (correct) or left (error) value. This is often referered to as being right biased (just like Haskell but unlike Scala). Because they are right biased they are iterable and monadic.

Bring in some static imports:

import static com.googlecode.totallylazy.Either.*; // Where the option factory methods live;

Now we can try some of the following:

right(1); // returns the correct value 1
left("error"); // returns the "error" value
right(1).isLeft(); // returns false
left("error").isRight(); // returns false
right(1).map(Math::cos); // returns right(0.5403023058681398)
left("error").map(Math::cos); // returns left("error")
for (T value : either(...)) System.out.print(value); // Only prints the "correct" value

In computing, a persistent data structure is a data structure that always preserves the previous version of itself when it is modified. Such data structures are effectively immutable, as their operations do not (visibly) update the structure in-place, but instead always yield a new updated structure. (A persistent data structure is not a data structure committed to persistent storage, such as a disk; this is a different and unrelated sense of the word "persistent.")

Peristent Data Structure @ Wikipedia. 2014

All peristent data structures in TotallyLazy implement the read only portion of the matching standard collection interface, so:

  • PersistentCollection extends Collection
  • PersistentMap extends Map
  • PersistentSet extends Set
  • PersistentList extends List

PersistentMap

import static com.googlecode.totallylazy.collections.PersistentMap.constructors.*;

PersistentMap<String, Integer> map = map("Dan", 1977, "Matt", 1978);
map.lookup("Dan"); // returns some(1977)
map.get("Dan"); // returns 1977
map.insert("Raymond", 1976); // returns a new map that shares state with the old map
map.put("Raymond", 1976); // Throw an IllegalMutationException
map.delete("Dan"); // returns map("Matt", 1978)
map.remove("Dan"); // Throw an IllegalMutationException

Download directly

You can always download the latest version directly from GitHub

Install using a dependency resolver

Add our repo to the repositories section in your pom.xml

<repository>
    <id>repo.bodar.com</id>
    <url>http://repo.bodar.com</url>
</repository>

Then add our dependency

<dependency>
    <groupId>com.googlecode.totallylazy</groupId>
    <artifactId>totallylazy</artifactId>
    <version>${LATEST_VERSION}</version>
</dependency>

Add the following URL to your runtime.dependencies file

mvn://repo.bodar.com/com.googlecode.totallylazy:totallylazy:pack|sources:${LATEST_VERSION}

Add to your buildfile:

repositories.remote << 'http://repo.bodar.com/'

TL = 'com.googlecode.totallylazy:totallylazy:jar:${LATEST_VERSION}'

compile.with TL

Add to your build.gradle file:

repositories {
    maven {
        url "http://repo.bodar.com/"
    }
}

dependencies {
    compile group:'com.googlecode.totallylazy', name:'totallylazy', version:'${LATEST_VERSION}'
}

Add a new resolver to your ivysettings.xml

<ibiblio name="bodar" root="http://repo.bodar.com/"
         m2compatible="true" useMavenMetadata="false" />

Then add the dependency to your ivy.xml file:

<dependency org="com.googlecode.totallylazy" name="totallylazy" rev="${LATEST_VERSION}"/>

Add to your build.sbt file:

resolvers += "bodar" at "http://repo.bodar.com/"

libraryDependencies += "com.googlecode.totallylazy" % "totallylazy" % "${LATEST_VERSION}"

Support

Friendly support is available at our Google Group or post a question on StackOverflow with tag totallylazy

Other languages

These are ports of TotallyLazy done by other people