Upgrade to Pro — share decks privately, control downloads, hide ads and more …

The grass is greener on the oher side

Sponsored · SiteGround - Reliable hosting with speed, security, and support you can count on. →

The grass is greener on the oher side

- Functional programming in general
- How they solve the null pointer exceptions?
- How they solve the exception delegation?

Avatar for Kárándi Tamás

Kárándi Tamás

December 23, 2012

Other Decks in Programming

Transcript

  1. A szomszéd fűje mindig zöldebb ... avagy hogyan csinálják a

    funkcionális világban Kárándi Tamás
  2. “functional programming is a programming paradigm that treats computation as

    the evaluation of mathematical functions and avoids state and mutable data”
  3. no mutable state no side effects no loops no null

    first class functions higher-order functions lambda expressions partially applied functions / currying referential transparency pattern matching ........monads
  4. Sir Tony Hoare “…but I couldn't resist the temptation to

    put in a null reference, simply because it was so easy to implement.”
  5. Null object design pattern Groovy : Safe navigation operator (?.)

    def user = User.find( "admin" ) //this might be null if 'admin' does not exist def streetName = user?.address?.street //streetName will be null if user or user.address is null // no NPE thrown Eiffel : Contracts Nice : Null type (?String vs String) ?String name = null; int len = name.length(); //Compile error int len = (name == null) ? 0 : name.length(); String name = "Some non-null string"; int len = name.length(); //Compiles
  6. naïve private interface Person { Contact getContact(); } private interface

    Contact { Address getAddress(); } private interface Address { String getZipCode(); } private static String getZipCode(Person person) { return person.getContact().getAddress().getZipCode(); }
  7. nested-if private interface Person { Contact getContact(); } private interface

    Contact { Address getAddress(); } private interface Address { String getZipCode(); } private static String getZipCode(Person person) { if (person != null) { Contact contact = person.getContact(); if (contact != null) { Address address = contact.getAddress(); if (address != null) { return address.getZipCode(); } else { return null; } } else { return null; } } else { return null; } }
  8. early-return private interface Person { Contact getContact(); } private interface

    Contact { Address getAddress(); } private interface Address { String getZipCode(); } private static String getZipCode(Person person) { if (person == null) { return null; } Contact contact = person.getContact(); if (contact == null) { return null; } Address address = contact.getAddress(); if (address == null) { return null; } return address.getZipCode(); }
  9. private interface Person { Option<Contact> getContact(); } private interface Contact

    { Option<Address> getAddress(); } private interface Address { Option<String> getZipCode(); } naïve again private static Option<String> getZipCode(Option<Person> person) { if (person.isNone()) { return none(); } Option<Contact> contact = person.some().getContact(); if (contact.isNone()) { return none(); } Option<Address> address = contact.some().getAddress(); if (address.isNone()) { return none(); } return address.some().getZipCode(); }
  10. functional public interface F<A, B> { B f(A a); }

    F<Person, Option<Contact>> p2c = new F<Person, Option<Contact>>() { @Override public Option<Contact> f(Person pers) { return pers.getContact(); } }; F<Contact, Option<Address>> c2a = new F<Contact, Option<Address>>() { @Override public Option<Address> f(Contact contact) { return contact.getAddress(); } }; F<Address, Option<String>> a2z = new F<Address, Option<String>>() { @Override public Option<String> f(Address addr) { return addr.getZipCode(); } };
  11. public <B> Option<B> bind(F<A, Option<B>> ff) { if (isNone()) {

    return none(); } return ff.f(value); } bind B A B
  12. F<Person, Option<Contact>> p2c = new F<Person, Option<Contact>>() { @Override public

    Option<Contact> f(Person pers) { return pers.getContact(); } }; F<Contact, Option<Address>> c2a = new F<Contact, Option<Address>>() { @Override public Option<Address> f(Contact contact) { return contact.getAddress(); } }; F<Address, Option<String>> a2z = new F<Address, Option<String>>() { @Override public Option<String> f(Address addr) { return addr.getZipCode(); } }; private static Option<String> getZipCode(Option<Person> person) { return person.bind(p2c).bind(c2a).bind(a2z); } monadic
  13. F<Person, Option<Contact>> p2c = new F<Person, Option<Contact>>() { @Override public

    Option<Contact> f(Person pers) { return pers.getContact(); } }; F<Contact, Option<Address>> c2a = new F<Contact, Option<Address>>() { @Override public Option<Address> f(Contact contact) { return contact.getAddress(); } }; F<Address, Option<String>> a2z = new F<Address, Option<String>>() { @Override public Option<String> f(Address addr) { return addr.getZipCode(); } }; F<Person, Option<Contact>> p2c = p -> p.getContact(); F<Contact, Option<Address>> c2a = c -> c.getAddress(); F<Address, Option<String>> a2z = a -> a.getZipCode(); private static Option<String> getZipCode(Option<Person> person) { return person.bind(p2c).bind(c2a).bind(a2z); } monadic with lambda expressions (Java8, ~2014) private static Option<String> getZipCode(Option<Person> person) { return person.bind(p -> p.getContact()).bind(c -> c.getAddress()).bind(a -> a.getZipCode()); }
  14. if (zipCode.isNone()) { System.out.println("No ZipCode found."); } else { System.out.println("ZipCode

    is : " + zipCode.get()); } //ZipCode is : 1234 //No ZipCode found. public interface OptionVisitor<A, R> { R visitNone(); R visitSome(A a); } String text = zipCode.accept(new OptionVisitor<String, String>() { @Override public String visitNone() { return "No ZipCode found."; } @Override public String visitSome(String a) { return "ZipCode is :" + a; } }); System.out.println(text); //ZipCode is : 1234 //No ZipCode found. Option<String> zipCode = getZipCode(person); System.out.println("Zipcode is : " + zipCode.toString()); //ZipCode is : Some(1234) //ZipCode is : None
  15. Option as iterable private interface Person { Option<Contact> getContact(); }

    private interface Contact { Option<Address> getAddress(); } private interface Address { Option<String> getZipCode(); } private static Option<String> getZipCode4(Option<Person> person) { for (Person p : person) { for (Contact c : p.getContact()) { for (Address a : c.getAddress()) { return a.getZipCode(); } } } return none(); }
  16. // OOP style public static Double sqroot(Integer i) { return

    Math.sqrt(i); } // FP style public static F<Integer, Double> sqroot = new F<Integer, Double>() { public Double f(Integer i) { return Math.sqrt(i); } }; // OOP Style public static Double sqroot(Integer i) throws NegativeNumberException { if (i < 0) { throw new NegativeNumberException("Square root doesn't work for negative numbers: " + i); } return Math.sqrt(i); }
  17. // OOP Style public static Double sqroot(Integer i) throws NegativeNumberException

    { if (i < 0) { throw new NegativeNumberException("Square root doesn't work for negative numbers: " + i); } return Math.sqrt(i); } //FP style public static F<Integer, Either<String, Double>> sqroot = new F<Integer, Either<String, Double>>() { public Either<String, Double> f(Integer i) { if (i < 0) { return Either.left("Square root doesn't work for negative numbers: " + i); } return Either.right(Math.sqrt(i)); } };
  18. // OOP public static Double multiplyBy2(Double d) { return d

    * 2; } public static void main(String[] args) { try { System.out.println(multiplyBy2(sqroot(3))); } catch (NegativeNumberException e) { //TODO: missing exception handling } }//3.4641016151377544 // FP style public static F<Double, Double> multiplyBy2 = new F<Double, Double>() { public Double f(final Double d) { return d * 2; } }; //FP style public static F<Integer, Either<String, Double>> sqroot = new F<Integer, Either<String, Double>>() { public Either<String, Double> f(Integer i) { if (i < 0) { return Either.left("Square root doesn't work for negative numbers: " + i); } return Either.right(Math.sqrt(i)); } };
  19. fmap public static <E, A, B> F<Either<E, A>, Either<E, B>>

    fmap(final F<A, B> f) { return new F<Either<E, A>, Either<E, B>>() { public Either<E, B> f(final Either<E, A> a) { if (a.isLeft()) { return Either.left(a.leftValue); } return Either.right(f.f(a.rightValue)); } }; } B A B A
  20. // OOP style public static Double multiplyBy2(Double d) { return

    d * 2; } public static void main(String[] args) { try { System.out.println(multiplyBy2(sqroot(3))); } catch (NegativeNumberException e) { //TODO: missing exception handling } }//3.4641016151377544 // FP style public static F<Double, Double> multiplyBy2 = new F<Double, Double>() { public Double f(final Double d) { return d * 2; } }; public static void main(String[] args) { F<Either<String, Double>, Either<String, Double>> liftedMultiplyBy2 = Eithers.fmap(multiplyBy2); Either<String, Double> res = liftedMultiplyBy2.f(sqroot.f(3)); System.out.println(res); } //Right (3.4641016151377544)
  21. List<String> names = List.list("Erzsi", "Piri", "Sari", "Juliska", "Rozali", "Ella", "Bella",

    "Juci", "Karolina"); List<Integer> nameLengths = names.map(length); nameLengths.foreach(print); //5 4 4 7 6 4 5 4 8 // A first-class function to get a String's length. public static F<String, Integer> length = new F<String, Integer>() { public Integer f(final String s) { return s.length(); } }
  22. package java.util.concurrent; public interface Callable<V> { V call() throws Exception;

    } package java.util.concurrent; public interface ExecutorService extends Executor { <T> Future<T> submit(Callable<T> task); ... } package java.util.concurrent; public interface Future<V> { V get(); } java.util.concurrent
  23. Strategy public static class Strategy<A> { private final F<Callable<A>, Future<A>>

    parallelStrategy; private Strategy(final F<Callable<A>, Future<A>> f) { this.parallelStrategy = f; } ... public <B> P1<List<A>> parMap(final F<B, A> f, final List<B> bs) ... }
  24. Identity Monad public abstract class P1<A> { public abstract A

    _1(); Strategy with the Identity Monad public static class Strategy<A> { private final F<P1<A>, P1<A>> parallelStrategy; private Strategy(final F<P1<A>, P1<A>> f) { this.parallelStrategy = f; } ... … public <B> P1<List<A>> parMap(final F<B, A> f, final List<B> bs) ... }
  25. Function composition public static <A, B, C> F<A, C> compose(final

    F<B, C> f, final F<A, B> g) { return new F<A, C>() { public C f(final A a) { return f.f(g.f(a)); } }; } (f ◦ g) x = f(g(x))
  26. liftM public static <A, B> F<A, P1<B>> lift(final F<A, B>

    f) { return new F<A, P1<B>>() { public P1<B> f(final A a) { return new P1<B>() { public B _1() { return f.f(a); } }; } }; } } B A B A
  27. parMap public <A> List<B> parMap(final F<A, B> userFunc, final List<A>

    items) { //the wrapped/lifted user function F<A, P1<B>> lazyFunc = lift(userFunc); //user function composed with the parallel strategy F<A, P1<B>> parallelFunc = compose(parallelStrategy(), lazyFunc); List<P1<B>> mappedItems = items.map(parallelFunc); P1<List<B>> lazyResult = sequence(mappedItems); return lazyResult._1(); } public static <A, B> F<A, P1<B>> lift(final F<A, B> f) { return new F<A, P1<B>>() { public P1<B> f(final A a) { return new P1<B>() { public B _1() { return f.f(a); } }; } }; } }
  28. Null Option Monad Exception Either Monad Logging Writer Monad Configuration

    Reader Monad Mutable objects State Monad Non-determinism List Monad Side effects IO Monad
  29. A A B A B A A B A B

    fmap unit bind lift B A B A