Registering functional programming with Java

I am new to functional programming and I am trying to use Lambda functions in Java to try and do FP. I know Java is not a good choice for learning Functional, but in my office I am limited to using Java and would like to apply some of these principles there.

I created an optional monad type thing in Java that looks something like this:

public abstract class Optional<T> implements Monad<T> {
    //unit function
    public static <T> Optional<T> of(T value) {
        return value != null ? new Present<T>(value) : Absent.<T>instance();
    }

    @Override
    public <V> Monad<V> flatMap(Function<T, Monad<V>> function) {
        return isPresent() ? function.apply(get()) : Absent.<V>instance();
    }
}

      

I use this to avoid nested checks null

in my code, a typical use case where I use this when I need something like firstNonNull

.

Using:

String value = Optional.<String>of(null)
                .or(Optional.<String>of(null)) //call it some reference
                .or(Optional.of("Hello"))      //other reference
                .flatMap(s -> {
                    return Optional.of(s.toLowerCase());
                })
                .get();

      

It works like a charm. Now the question is how to combine the entry with this? What if I need to know which of these links was used? This is useful if there is semantics associated with these links and I need to register that this link was not found by trying another option.

Log:

some reference is not present and some other business case specific log

      

Can this be implemented in Java? I tried to read some possible solutions from the internet and found the Writer

Haskell monad but I got confused and couldn't follow.

EDIT

Link to gist

+3


source to share


3 answers


The clean solution for this is monoid composition.

Combination of monoids

A monoid is an associative binary operation with an identifier. The type Optional<A>

forms a monoid for any A

:

https://functionaljava.ci.cloudbees.com/job/master/javadoc/fj/Monoid.html#firstOptionMonoid--

In your case it Monoid<Optional<A>>

will be implemented using or

as sum

and Absent

how zero

, so it yourMonoid.sum(x, y)

should be the same as x.or(y)

.

Now you want to combine this with another monoid made up of your magazine. So let's say you are using simple String

as your log. Well, String

forms a monoid, where sum

is string concatenation and zero

is an empty string.

You want to combine the monoid String

with firstOptionMonoid

. For this, you need a tuple type. Functional Java has a tuple type calledP2

. Here's how you combine the two monoids (this really needs to be added to the class Monoid

, send a pull request!):

import fj.*;
import static fj.P.p;
import static fj.Monoid.*;

public final <A,B> Monoid<P2<A,B>> compose(Monoid<A> a, Monoid<B> b) {
  return monoid(
    x -> y -> p(a.sum(x._1, y._1), b.sum(x._2, y._2)),
    p(a.zero, b.zero));
}

      

Composite monoid then (in FJ):



Monoid<P2<Option<A>, String>> m = compose(firstOptionMonoid<A>, stringMonoid)

      

Now, you don't always want to add a journal. You want it to depend on whether a value is present or not in Option

. To do this, you can write a specialized method:

public final P2<Option<A>, String> loggingOr(
  P2<Option<A>, String> soFar,
  Option<A> additional,
  String msg) {
    return soFar._1.isDefined ?
      soFar :
      m.sum(soFar, p(additional, msg))
  } 

      

I recommend looking more at monoids. They are a very versatile tool, and they are one of the few purely functional constructs that are actually enjoyable to use in Java. If you don't mind learning in Scala, I wrote a book called Functional Programming in Scala and the chapter on monoids is just available online for free.

Combination of monads

But now you are working with a composite type P2<Option<A>, String>

, not just with Option<A>

, and this type does not come with flatMap

. What you would really like (if Java can do it, but it can't) is to use a monad Writer<String, _>

with a monad type transformer OptionT

. Imagining for a moment that Java can have monadic transformers, the type P2<Option<A>, String>

would be equivalent to the type OptionT<Writer<String, _>, A>

where _

the partially applied type constructor indicates (obviously not valid Java).

The only Java solution is to combine these monads in first-order order:

import fj.data.Writer

public abstract class OptionWriter<W, A> {
  abstract Writer<W, Option<A>> writer;
  public <B> OptionWriter<W, B> flatMap(Function<A, OptionWriter<B>>) {
    ...
  }
  public static <M, T> OptionWriter<M, T> unit(t: T) {
    return Writer.unit(Option.unit(t))
  }
}

      

+1


source


I would use varargs approach, it would be easier to track and shorten the entries.

public static <T> Optional<T> of(T... value) {
    for(int i=0;i<values.length;i++) {
        if (value[i] != null) {
            // log that value[i] was chosen
            return new Present<T>(value[i]);
        }
    }
    // log all was null
    return Absent.<T>instance();
}

      



In your example

String value = Optional.of(null, null, "Hello").get();

      

0


source


At this point, you have two implementations Optional

, Present

and Absent

. I suggest introducing another type LoggingAbsent

that behaves like Absent

but logs any operation that reacts inversely.

The key is deciding whether to return one of these types. For example. when converting a null to a value Optional

it would be helpful to return an instance LoggingAbsent

. But when called map

on, Optional

it would make sense that the implementation LoggingAbsent

registers the operation and returns the result unregistered Absent

, so that only the first operation in the chain reports a failure, and all subsequent operations back out silently.

You can also support explicit selection by providing an alternative factory method for logging and non-logging Optional

.

0


source







All Articles