Skip to content

Instantly share code, notes, and snippets.

@gigamonkey
Created October 31, 2024 03:46
Show Gist options
  • Save gigamonkey/5d35c597cafa49f284d66e7fa5f00116 to your computer and use it in GitHub Desktop.
Save gigamonkey/5d35c597cafa49f284d66e7fa5f00116 to your computer and use it in GitHub Desktop.
Demo of lift functions in Java
import java.util.*;
import java.util.function.*;
public class Lift {
public static interface Expression {
public Optional<Double> evaluate();
}
// This is a higher-order function that takes a function (i.e. an istance of a
// functional interface) and abstracts the pattern of flat mapping and mapping
// we discussed today for functions that take two arguments.
//
// In this function we can use the existing DoubleBinaryOperator and
// BinaryOperator<T> from java.util.function.
//
// The name liftM2 comes from the Haskell programming language which is big
// into this kind of thing. I think the idea is that you're "lfiting" the
// function from its earthly realm of dealing with actual values into a higher
// plane of dealing with Optionals of values. The 2 stands for the number of
// arguments.
public static BinaryOperator<Optional<Double>> liftM2(DoubleBinaryOperator fn) {
return (o1, o2) -> o1.flatMap(d1 -> o2.map(d2 -> fn.applyAsDouble(d1, d2)));
}
// Now let's define two new functional interfaces as analogs to
// DoubleBinaryOperator and BinaryOperator<T> but for three-arguments
// functions:
public static interface DoubleTrinaryOperator {
public double apply(double d1, double d2, double d3);
}
public static interface TrinaryOperator<T> {
public T apply(T a, T b, T c);
}
// Now we can define liftM3 which can lift a three-arg function into the Optional realm.
public static TrinaryOperator<Optional<Double>> liftM3(DoubleTrinaryOperator fn) {
return (o1, o2, o3) -> o1.flatMap(d1 -> o2.flatMap(d2 -> o3.map(d3 -> fn.apply(d1, d2, d3))));
}
// This is kind of a goofy example because the whole point of why you went
// down this path was to trap the case where the discriminant is negative. But
// this shows off the liftM3 mechanism.
record QuadraticfFormula(Expression a, Expression b, Expression c) implements Expression {
public Optional<Double> evaluate() {
return liftM3(this::formula).apply(a.evaluate(), b.evaluate(), c.evaluate());
}
private double formula(double a, double b, double c) {
return (-b + Math.sqrt(Math.pow(b, 2) - 4 * a * c)) / (2 * a);
}
}
record Number(double value) implements Expression {
public Optional<Double> evaluate() { return Optional.of(value); }
}
public static void main(String[] args) {
System.out.println(new QuadraticfFormula(new Number(5), new Number(6), new Number(1)).evaluate());
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment