Skip to content

Instantly share code, notes, and snippets.

@noullet
Last active August 29, 2015 14:08
Show Gist options
  • Save noullet/9f94bb8fdec8f8c7c369 to your computer and use it in GitHub Desktop.
Save noullet/9f94bb8fdec8f8c7c369 to your computer and use it in GitHub Desktop.
applyOptional in Java to simulate liftA3
public class C {
private String t;
private Integer u;
private String v;
public C(String t, Integer u, String v) {
this.t = t;
this.u = u;
this.v = v;
}
public String getT() {
return t;
}
public Integer getU() {
return u;
}
public String getV() {
return v;
}
}
import java.util.Optional;
@FunctionalInterface
// This interface is missing in Java
// Some languages / libs provide Function1 -> FunctionN out of the box, e.g. Scala up to 22
public interface Function3<T, U, V, C> {
C apply(T t, U u, V v);
// This is far from ideal because it works only with Optional
// whereas ideally it could be written once for all flatMappable things (more or less, Monads).
// Actually it would work with even lighter abstract structures: Applicative Functors
// see the liftA3 function in Haskell: https://www.haskell.org/hoogle/?hoogle=liftA3
// Unfortunately Java doesn't support higher-kinded polymophism: you cannot depend on generic parameters
// that have themselves generic parameters (here F<V> where F would be itself any instance of Applicative Functor.
// Finally, this definition should not be here but rather in the Applicative Functor "interface".
default Optional<C> applyOptional(Optional<T> optT, Optional<U> optU, Optional<V> optV) {
return optT.flatMap(t ->
optU.flatMap(u ->
optV.map(v ->
this.apply(t, u, v)
)
)
);
}
}
import java.util.Optional;
import java.util.function.Consumer;
public class Main {
public static void main(String[] args) {
// Get the constructor reference and make it instance of Function3
Function3<String, Integer, String, C> newC = C::new;
Consumer<C> printC = (c ->
System.out.println(c.getT() + " " + c.getU() + " " + c.getV())
);
// All optional parameters are provided
Optional<String> optT = Optional.of("foo");
Optional<Integer> optU = Optional.of(42);
Optional<String> optV = Optional.of("bar");
Optional<C> optC = newC.applyOptional(optT, optU, optV);
optC.ifPresent(printC); // prints "foo 42 bar"
// One optional parameter is empty
Optional<Integer> optEmpty = Optional.empty();
Optional<C> optC2 = newC.applyOptional(optT, optEmpty, optV);
optC2.ifPresent(printC); // do nothing
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment