Functors in Java

Hello there!

In the functional style approach is very common to mapping objects and types to another ones, mainly in stream transformation sequences (Akka Streams and RxJava for example). One safe way to do it is put this object, stream, data structure whatever in a protected container that allows us to execute mapping operations with functions. Here is where Functors can be very useful.

Before start, let’s see some code to clarify:

@FunctionalInterface
public interface Functor<T, F extends Functor> {

    private final T value;

    public Identity(T value) {
        this.value = value;
    }

    @Override
    public  Identity<?> map(Function<T, R> f) {
        final R result = f.apply(value);
        return new Identity<>(result);
    }
}

The above class Identity is a functor that just holds a value, and all you can do with that value is transforming it inside map method, but there’s no way to extract it, this is considered beyond the scope of a pure functor. The only way to interact with a functor is by applying sequences of immutable and type-safe transformations:

Identity idString = new Identity<>("something interesting!");
Identity idInteger = idString.map(String::length);

Or fluently:

Identity<byte[]> idBytes = new Identity<>(customer)
        .map(Customer::getAddress)
        .map(Address::street)
        .map((String s) -> s.substring(0, 3))
        .map(String::toLowerCase)
        .map(String::getBytes);

That’s so beauty, right? But you will probably also ask yourself, why I need a wrapper that not allow extracting the contents back? Remember, a Functor always returns a new Functor. Functors abstraction can be very useful with other concepts, for example, the Java 8 Optional is a functor with map() method. Let’s implement a kind of Optional with our simple Functor functional interface:

public class FOptional implements Functor<T,FOptional<?>> {

    private final T valueOrNull;

    private FOptional(T valueOrNull) {
        this.valueOrNull = valueOrNull;
    }

    public  FOptional map(Function<T,R> f) {
        if (valueOrNull == null)
            return empty();
        else
            return of(f.apply(valueOrNull));
    }

    public static  FOptional of(T a) {
        return new FOptional(a);
    }

    public static  FOptional empty() {
        return new FOptional(null);
    }
}

It’s still simple but more interesting, because  the FOptional functor can holds a value, but just as well it might be empty. It’s a type-safe way of preventing NullPointerException. As I wrote in this post https://viniciusluisr.wordpress.com/2016/11/06/monads-in-java/ the Java 8 Optional is also a monad, so we can say that the Optional is both a Functor and a Monad, that is a powerful mixing the two concepts.

A functor may not necessarily involve only one value:

import com.google.common.collect.ImmutableList;

class FList implements Functor<T, FList<?>> {

    private final ImmutableList list;

    FList(Iterable value) {
        this.list = ImmutableList.copyOf(value);
    }

    @Override
    public  FList<?> map(Function<T, R> f) {
        ArrayList result = new ArrayList(list.size());
        for (T t : list) {
            result.add(f.apply(t));
        }
        return new FList<>(result);
    }
}

The above functor works in the same way, transforming T to R and returns a new FList always, but the behavior is different. Now we can apply a transformation in each list element. So if you have a Categories list and want to list their products, is very simple:

FList streets = categories
        .map(Category::getProducts)
        .map(Product::getPrice);

It’s no longer as simple as saying categories.getProduct().getPrice(), you can’t invoke getProduct on a customers collection, you must invoke that on each object and then place it back in a collection.
So maybe you are wondering why I iterate over categories list manually inside our Functor using map operation rather than using Java 8 Streams API:
categories.stream.map(Category::getProducts).collect(Collectors.toList)? But, if I told you java.util.stream.Stream is a functor as well? And by the way, also a monad?

Now, I think you should see the benefits of functors. The abstract way to wrap internal representations and provide consistent and easy to use API over any data structure. Let’s see another example that implements a Promise functor. A Promise is a kind of Future that an “promised” value will appear some time in the future:

Promise customer = //...
        Promise<byte[]> bytes = customer
        .map(Customer::getAddress)
        .map(Address::street)
        .map((String s) -> s.substring(0, 5))
        .map(String::toUpperCase)
        .map(String::getBytes);

Looks familiar?  That’s the point! Enough to say that we are very close to implementing CompletableFuture from Java 8 and we almost discovered Observable from RxJava. Back to the example, the Promise doesn’t holds a value just yet. It promises to have such value in the future, but we can still map over such functor, just like we did with FOptional and FList.

Invoking customer.map(Customer::getAddress) yields Promise

which means map is non-blocking. customer.map(Customer::getAddress) wont wait for the underlying customer promise to complete.
Instead it returns another promise, of a different type. When upstream promise completes, downstream promise applies a function passed to map() and passes the result downstream.
Suddenly our functor allows us to pipeline asynchronous computations in a non-blocking manner. But you do not have to understand or learn that – because Promise is a functor, it must follow syntax and laws.

There are many other great examples of functors, for example representing value or error in a compositional manner, but the main idea of this post is show you the concept and the abstraction of functors, and in functional programming, functors are in many other concepts and structures.

Enjoy your functors!

You can see the complete code of the above examples in the following link:

https://github.com/viniciusluisr/simple-functor

Advertisements