Last active
August 29, 2015 14:08
-
-
Save noullet/9f94bb8fdec8f8c7c369 to your computer and use it in GitHub Desktop.
applyOptional in Java to simulate liftA3
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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) | |
) | |
) | |
); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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