Skip to content

Latest commit

 

History

History
193 lines (157 loc) · 8.34 KB

features.adoc

File metadata and controls

193 lines (157 loc) · 8.34 KB

Features

First-Class Functions

Functional Java provides generic interfaces and abstract classes that serve as first-class functions or closures, entirely within Java’s type system (i.e. without reflection or byte-code manipulation). The library centers around the F interface, which models a function from type A to type B.

Functions are written with anonymous class syntax:

// Regular Style
Integer timesTwo(Integer i) { return i * 2; }
// Functional Style
F timesTwo = new F() { public Integer f(Integer i) { return i * 2; } }

First-class functions can be composed and passed as arguments to higher-order functions:

// Regular Style
Integer timesTwoPlusOne(Integer i) { return plusOne(timesTwo(i)); }
// Functional Style
F timesTwoPlusOne = plusOne.o(timesTwo);

And mapped over collections:

//Regular Style
List oneUp = new ArrayList();
for (Integer i: ints) oneUp.add(plusOne(i));
// Functional Style
List oneUp = ints.map(plusOne);

Functions up to arity-8 are supported, allowing elimination of nested control constructs:

// Regular Style
Integer product = 1;
for (Integer x: ints) product = x * product;
List products1 = new ArrayList();
for (int x = 0; x < ints.size(); x++) {
  for (int y = 0; y <= x; y++) {
    products.add(ints.get(x) * ints.get(y);
  }
}
List products2 = new ArrayList();
for (Integer x: ints) {
  for (Integer y: ints) {
    products.add(x * y);
  }
}
// Functional Style
Integer product = ints.foldLeft(1, multiply);
List products1 = ints.tails().apply(ints.map(multiply));
List products2 = ints.bind(ints, multiply);

Immutable Datastructures

Functional Java implements many immutable datastructures, such as

  • Singly-linked lists (fj.data.List)

  • Non-strict, potentially infinite, singly-linked list (fj.data.Stream)

  • Non-strict, potentially infinite Strings (fj.data.LazyString)

  • A wrapper for arrays (fj.data.Array)

  • A wrapper for any Iterable type (fj.data.IterableW)

  • Immutable ordered sets (fj.data.Set)

  • Multi-way trees — a.k.a. rose trees, with support for infinite trees (fj.data.Tree)

  • Immutable Map, with single-traversal search-and-update (fj.data.TreeMap)

  • Type-safe heterogeneous lists (fj.data.hlist)

  • Pointed lists and trees (fj.data.Zipper and fj.data.TreeZipper)

These datatypes come with many powerful higher-order functions, such as map (for functors), bind (monads), apply and zipWith (applicative functors), and cobind (for comonads).

Efficient conversions to and from the standard Java Collections classes are provided, and java.util.Iterable is implemented where possible, for use with Java’s foreach syntax.

Optional Values (type-safe null)

The library provides a datatype for variables, parameters, and return values that may have no value, while remaining type-safe.

// Using null
String val = map.get(key);
if (val == null || val.equals("")) val = "Nothing";
return val;
// Using Option
return fromString(map.get(key)).orSome("Nothing");

Optional values are iterable, so they play nicely with foreach syntax, and they can be composed in a variety of ways. The fj.Option class has a plethora of methods for manipulating optional values, including many higher-order functions.

Product Types

Joint union types (tuples) are products of other types. Products of arities 1-8 are provided (fj.P1 - fj.P8). These are useful for when you want to return more than one value from a function, or when you want to accept several values when implementing an interface method that accepts only one argument. They can also be used to get products over other datatypes, such as lists (zip function).

Example:

// Regular Java
public Integer albuquerqueToLA(Map> map) {
  Map m = map.get("Albuquerque");
  if (m != null) return m.get("Los Angeles"); // May return null.
}
// Functional Java with product and option types.
public Option albuquerqueToLA(TreeMap, Integer>() map) {
  return m.get(p("Albuquerque", "Los Angeles"));
}

Disjoint Union Types

By the same token, types can be added by disjoint union. Values of type Either<A, B> contain a value of either type A or type B. This has many uses. As an argument type, it allows a single argument to depend on the type of value that is received (effectively overloading the method even if the interface is not designed to do that). As a return type, it allows you to return a value of one of two types depending on some condition. For example, to provide error handling where you are not allowed to throw `Exception`s:

// Meanwhile, inside an iterator implementation...
public Either next() {
  String s = moreInput();
  try {
    return Either.right(Integer.valueOf(s));
  } catch (Exception e) {
    return Either.left(Fail.invalidInteger(s));
  }
}

The Either class includes a lot of useful methods, including higher-order functions for mapping and binding over the left and right types, as well as Iterable implementations for both types.

Higher-Order Concurrency Abstractions

Functional Java includes Parallel Strategies (fj.control.parallel.Strategy) for effectively decoupling concurrency patterns from algorithms. Strategy provides higher-order functions for mapping and binding over collections in parallel:

Strategy s = simpleThreadStrategy();
List ns = range(Integer.MIN_VALUE, Integer.MIN_VALUE + 10).map(negate).toList();
List bs = s.parMap(ns, isPrime);

Also included is an implementation of the actor model (fj.control.parallel.Actor and QueueActor), and Promise, which is a composable and non-blocking version of java.util.concurrent.Future.

Abstractions

Functional Java provides abstractions for the following types:

  • Basic Data Structures

    • Functions with arity 1 to 8 (fj.F).

    • Functions with arity 0 to 8 that can produce exceptions (fj.TryCatch).

    • Products with arity 1 to 8 (fj.P).

    • Unit type (fj.Unit).

    • Optional value - type-safe null (fj.data.Option).

    • Disjoint union data type - compositional exception handling (fj.data.Either).

    • Validation - right biased compositional exception handling (fj.data.Validation).

    • Void - a logically uninhabited data type.

  • Immutable Collections

    • Array wrapper (fj.data.Array).

    • Immutable, in-memory singly linked list (fj.data.List).

    • Immutable lazy singly linked list (fj.data.Stream).

    • A package (fj.data.fingertrees) providing 2-3 finger trees for a functional representation of persistent sequences, supporting access to the ends in amortized O(1) time.

    • Type-safe heterogeneous list (fj.data.hlist) for lists of elements of differing types without sacrificing type-safety.

    • Immutable set implementation using a red/black tree (fj.data.Set).

    • Immutable multi-way tree - aka rose tree (fj.data.Tree).

    • Immutable tree-map using a red/black tree implementation (fj.data.TreeMap).

    • Difference lists, a highly performant list.

  • Other

    • Monoid (fj.Monoid).

    • Semigroup (fj.Semigroup).

    • Natural number data type (fj.data.Natural).

    • Random number generator using a linear congruential generator (fj.LcgRng).

    • Reader, Writer and State monads (fj.data.Reader,fj.data.Writer, fj.data.State).

    • Input/Output monad for abstracting IO (fj.IO).

    • Monadic parser combinators for writing parsers by combining smaller parsers using composition.

    • Conversion of data types to/from standard Java types.

    • Conversion between FunctionalJava and Java 8 specific types.

    • Configurable equality and hash-code for HashMap and HashSet.

    • Zipper implementations for streams and trees.

    • Automated specification-based testing framework (fj.test).

    • Fully operational Actors for parallel computations (fj.control.parallel) and layered abstractions such as parallel-map, map-reduce, parallel-zip.

    • Optics for updating immutable data including lens, prism, iso, optional, traversal, getter, fold and setter. Inspired by the Scala Monocle library (https://github.com/julien-truffaut/Monocle) and the Haskell lens library (https://github.com/ekmett/lens).