- https://www.vavr.io/vavr-docs/#_lifting
- https://static.javadoc.io/io.vavr/vavr/0.9.3/io/vavr/PartialFunction.html
- https://github.com/mtumilowicz/java11-vavr-function-lifting
- on the workshop we will try to fix failing
Workshop - answers:
Answers(same tests as inWorkshopbut correctly solved)
- a partial function from
XtoYis a functionf: K → Y, for someK c X. Forx e X\Kfunction is undefined - it generalizes the concept of a function
f: X → Yby not forcingfto map every element ofXto an element ofY- that means a partial function works properly only for some input values
- in programming, if the function is called with a disallowed input value, it will typically throw an exception
- in particular - every function that throws an exception is a partial function
- partial function (to set intuition)
int do(int positive) { if (positive < 0) { throw new IllegalArgumentException("Only positive integers are allowed"); } // other stuff } - vavr's partial function interface
public interface PartialFunction<T, R> { R apply(T t); boolean isDefinedAt(T value); // tests if a value is contained in the function's domain }- the caller is responsible for calling the method
isDefinedAt()before this function is applied to the value - if the function is not defined for a specific value,
apply()may produce an arbitrary result- in particular - random values
- more specifically - it is not guaranteed that the function will throw an exception
do(int positive)mentioned above - rewritten with vavr:class RandomIdentity implements PartialFunction<Integer, Integer> { @Override public Integer apply(Integer o) { if (!isDefinedAt(o)) { throw new IllegalArgumentException("Only positive integers are allowed"); } // other stuff } @Override public boolean isDefinedAt(Integer value) { return nonNull(value) && value > 0; } }
- the caller is responsible for calling the method
- In programming - we usually lift partial function
f: (K c X) -> Ytog: X -> Option<Y>in such a manner:- a lifted function returns
Some, if the function is invoked with allowed input valuesg(x).get() = f(x)onK
- a lifted function returns
Noneinstead of throwing an exception, if the function is invoked with disallowed input valuesg(x) = Option.none()forx e X\K
- a lifted function returns
In vavr we have two approaches to lifting:
- lifting function with
OptionFunction2<Integer, Integer, Integer> divide = (a, b) -> a / b; Function2<Integer, Integer, Option<Integer>> lifted = Function2.lift(divide); lifted.apply(1, 0) == Option.none() lifted.apply(4, 2) == Option.some(2) - lifting function with
TryFunction2<Integer, Integer, Integer> divide = (a, b) -> a / b; Function2<Integer, Integer, Try<Integer>> lifted = Function2.liftTry(divide); lifted.apply(1, 0).failure lifted.apply(1, 0).cause.class == ArithmeticException lifted.apply(4, 2) == Try.success(2) Tryis nearly always better, because it contains specific exception, which is often a very valuable information, we do not want to lose