Skip to content

mtumilowicz/java11-vavr093-partial-function-lifting-workshop

Repository files navigation

Build Status License: GPL v3

java11-vavr093-partial-function-lifting-workshop

project description

theory in a nutshell

  • a partial function from X to Y is a function f: K → Y, for some K c X. For x e X\K function is undefined
  • it generalizes the concept of a function f: X → Y by not forcing f to map every element of X to an element of Y
    • 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;
          }
      }
      
  • In programming - we usually lift partial function f: (K c X) -> Y to g: X -> Option<Y> in such a manner:
    • a lifted function returns Some, if the function is invoked with allowed input values
      • g(x).get() = f(x) on K
    • a lifted function returns None instead of throwing an exception, if the function is invoked with disallowed input values
      • g(x) = Option.none() for x e X\K

conclusions in a nutshell

In vavr we have two approaches to lifting:

  • lifting function with Option
    Function2<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 Try
    Function2<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)
    
  • Try is nearly always better, because it contains specific exception, which is often a very valuable information, we do not want to lose

About

Vavr Partial Function and function lifting workshops.

Topics

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published