Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

Functional programming

796 views

Published on

  • Be the first to comment

Functional programming

  1. 1. Functional Programming ExperTalks 2015-09-11 Leena Bora, Equal Experts Christian Hujer, Nelkinda Software Craft
  2. 2. Flying to other stars
  3. 3. Methods that don’t work
  4. 4. What are the problems? No (known) medium in space. No chemicals in space (i.e. no oxygen). Many more. One of the biggest: Speed of Light = speed limit
  5. 5. Can we “break” the speed limit? Sci-Fi authors: “Yes” Scientists: “No!”
  6. 6. Miguel Alcubierre from Mexico …
  7. 7. … watched Star Trek TNG …
  8. 8. … and then had the idea for this: ds2 = -(α2 - βi βi) dt2 + 2βi dxi dt + γij dxidxj which I don’t really understand, but if it works...
  9. 9. … it would allow this
  10. 10. Further Information Alcubierre Drive (Wikipedia) Miguel Alcubierre (Wikipedia) “The warp drive: hyper-fast travel within general relativity” - Miguel Alcubierre, 1994 Warp Drive (Wikipedia) RF resonant cavity thruster (Wikipedia)
  11. 11. History of Functional Programming
  12. 12. 1903 - 1995 1930s 𝜆 calculus 1936 untyped 𝜆 calculus 1940 simple typed 𝜆 calculus Alonzo Church: Lambda-Calculus
  13. 13. John McCarthy: Lisp 1927 - 2011 1958 Lisp 1959 Garbage Collection 1961 Utility Computing (Cloud!) 1971 Turing Award
  14. 14. John Backus 1924 - 2007 1957 FORTRAN 1960 Backus-Naur-Form 1977 Turing Award, FP “Can Programming be Liberated from the von Neumann Style?”
  15. 15. Milestones 1936 Lambda Calculus (Church & Rosser) 1958 Lisp (McCarthy) 1963 Algol 60 (Naur et al) 1966 ISWIM (Landin) 1969 NPL, ML, HOPE 1973 SASL 1986 Miranda 1992 Haskell 2007 Clojure 2013 Java 8
  16. 16. Moore’s Law (1965) Gordon E. Moore ●*1929 ●Co-founder of Intel ~ “Number of transistors doubles every 18 months” ⇒ More GHz But for how long?
  17. 17. Amdahl’s Law (1967) Gene Amdahl ●*1922 ●IBM Mainframes ●Amdahl Corporation
  18. 18. Amdahl’s Law Given ●𝑛 ∊ ℕ, the number of threads of execution ●B ∊ [0, 1], strictly serial fraction of algorithm Time T(𝑛) it takes to finish with n threads is T(𝑛) = T(1)(B + 1/𝑛 (1 − B)) Therefore, the theoretical speedup S(𝑛) is S(𝑛) = T(1) / T(𝑛) = 1 / (B + 1/𝑛 (1 - B))
  19. 19. Gustafson’s Law John Gustafson ●*1955 ●HPC ●Computer Clusters
  20. 20. Gustafson’s Law Given a the sequential time, b the parallel time, P the number of processors, a + b single thread time a + P b sequential time (a + P b) / (a + b) speedup α = a / (a + b) sequential fraction S(P): S(P) = α + P (1 − α) = P − α (P − 1)
  21. 21. To run fast Parallelism Avoid Race conditions
  22. 22. Alonzo Church (Wikipedia) John McCarthy (Wikipedia) John Backus (Wikipedia) Functional Programming History (Wikipedia) Some History of Functional Programming Languages (D. A. Turner) Gordon Moore (Wikipedia) Moore’s Law (Wikipedia) Gene Amdahl (Wikipedia) Amdahl’s Law (Wikipedia) John Gustafson (Wikipedia) Gustafson’s Law (Wikipedia) History of Functional Programming References
  23. 23. Programming Paradigm It is all about “functions” What is Functional Programming?
  24. 24. f(x) = 2x + 3 f(2) = 4 + 3 = 7 The value of x will never change inside a mathematical function. Same input, same output - all the time! Call f() multiple times, without any side-effects. We don’t have to recalculate f(2), replace occurrence of f(2) with 7 (Referential Transparency)
  25. 25. f(x) = 2x² − 2x + 3
  26. 26. Pure Function public int calculate(int x) { return (2 * x) + 3; } calculate(2) = 7 calculate(2) = 7
  27. 27. public class Account { int balance; public Account(int balance) { this.balance = balance; } public int credit(int amount) { balance = balance + amount; return balance; } } Account account = new Account(100); account.credit(500); // → balance == 600 account.credit(500); // → balance == 1100
  28. 28. class Account { final int balance; public Account(int balance) { this.balance = balance; } public Account credit(int amount) { return new Account(balance + amount); } } Account account = new Account(100) Account currentAccountState = account.credit(500) ===> currentAccountState(600) Account newAccountState = currentAccountState.credit(500) ===> newAccountState(1100) account.credit(500) ===> currentAccount(600)
  29. 29. Modifying global variable / data structure Modifying input value Throwing an exception Read / Write (File, Console, Database) Communication with External System Side Effects
  30. 30. Thin layer of impure functions (DB, I/O, exceptions) Pure functions at the core
  31. 31. Why Pure Functions? No Side-effects A function f is said to be a “pure function” if f(x) is “referentially transparent” Memoization Execution Order can be rearranged (!) Local Reasoning Parallel Execution public int square (int number) { return number * number; }
  32. 32. Functional Programming is so called because a program consists of “pure functions” & “functions”
  33. 33. Where FP and OOP meet for the DIP Higher-Order Functions
  34. 34. No function as argument, and no function as return First-Order vs Higher-Order Function as argument, or function as return (or both)
  35. 35. Workarounds if unavailable Function Pointer Types Function Pointers One-Element Interfaces Objects
  36. 36. 1 #include <stdlib.h> // qsort 2 #include <string.h> // strcmp 3 4 static int strptrcmp(const void *l1, const void *l2) { 5 return strcmp(*(const char **)l1, *(const char **)l2); 6 } 7 8 static char **lines; 9 static size_t numberOfLines; 10 11 qsort(lines, numberOfLines, sizeof(char *), strptrcmp); Higher-Order Functions in C Example: qsort()
  37. 37. 1 enum AccountComparator implements Comparator<Account> { 2 INSTANCE; 3 public int compare(Account a1, Account a2) { 4 return Integer.compare(a1.balance, a2.balance); 5 } 6 } 7 8 List<Account> accounts = …; 9 accounts.sort(AccountComparator.INSTANCE); Higher-Order Functions in Java Example: List.sort()
  38. 38. Method References Lambda Expressions Syntactic sugar for higher-order functions. Underneath: generated anonymous classes. Improvements in Java 8
  39. 39. 1 class Account { 2 int balance; 3 Account(int balance) { this.balance = balance; } 4 public static final Comparator<Account> BY_BALANCE = 5 new Comparator<Account>() { 6 public int compare(Account a1, Account a2) { 7 return compare(a1.balance, a2.balance); 8 } 9 }; 10 } 11 12 List<Account> accounts; 13 accounts.sort(BY_BALANCE); Java 5 Anonymous Class
  40. 40. 1 class Account { 2 int balance; 3 Account(int balance) { this.balance = balance; } 4 public static final Comparator<Account> BY_BALANCE = 5 6 ( a1, a2) -> { 7 return compare(a1.balance, a2.balance); 8 } 9 ; 10 } 11 12 List<Account> accounts; 13 accounts.sort(BY_BALANCE); Java 8 Block Lambda
  41. 41. 1 class Account { 2 int balance; 3 Account(int balance) { this.balance = balance; } 4 public static final Comparator<Account> BY_BALANCE = 5 6 ( a1, a2) -> 7 compare(a1.balance, a2.balance) 8 9 ; 10 } 11 12 List<Account> accounts; 13 accounts.sort(BY_BALANCE); Java 8 Expression Lambda
  42. 42. 1 class Account { 2 int balance; 3 Account(int balance) { this.balance = balance; } 4 public static final Comparator<Account> BY_BALANCE = 5 (a1, a2) -> compare(a1.balance, a2.balance); 6 } 7 8 List<Account> accounts; 9 accounts.sort(BY_BALANCE); Java 8 Expression Lambda
  43. 43. 1 final JFrame frame = new JFrame("Hello"); 2 final JButton button = new JButton("Click me!"); 3 button.addActionListener(new ActionListener() { 4 @Override 5 public void actionPerformed(final ActionEvent e) { 6 showMessageDialog(frame, "Hello, world!"); 7 } 8 }); 9 frame.add(b); 10 frame.pack(); 11 frame.setDefaultCloseOperation(DISPOSE_ON_CLOSE); 12 frame.setVisible(true); Single Method Callback Java 5 Anonymous Class
  44. 44. 1 final JFrame frame = new JFrame("Hello"); 2 final JButton button = new JButton("Click me!"); 3 button.addActionListener(e -> 4 5 6 showMessageDialog(frame, "Hello, world!") 7 8 ); 9 frame.add(b); 10 frame.pack(); 11 frame.setDefaultCloseOperation(DISPOSE_ON_CLOSE); 12 frame.setVisible(true); Single Method Callback Java 8 Expression Lambda
  45. 45. Java 8 Instance Method References 1 public class Application { 2 Application() { 3 final JMenuItem open = new JMenuItem("Open..."); 4 final JMenuItem save = new JMenuItem("Save"); 5 open.addActionListener(this::open); 6 save.addActionListener(this::save); 7 } 8 private void open(final ActionEvent e) { 9 // ... 10 } 11 private void save(final ActionEvent e) { 12 // ... 13 } 14 }
  46. 46. Java 8 Stream.forEach() 1 import java.io.*; 2 import static java.lang.System.*; 3 4 public class Sort { 5 private static BufferedReader getIn() { 6 return new BufferedReader(new InputStreamReader(in)); 7 } 8 public static void main(final String... args) throws IOException { 9 try (final BufferedReader in = getIn()) { 10 in.lines().sorted().forEach(out::println); 11 } 12 } 13 }
  47. 47. What if you want to reuse A without B? Dependency Inversion Principle Component A Component B
  48. 48. What if you want to reuse A without B? Dependency Inversion Principle Component A Component B Sort Article
  49. 49. What if you want to reuse A without B? Dependency Inversion Principle Component A Component B Sort ArticleComparable
  50. 50. Higher Order Functions Are a form of polymorphism Serve the Dependency Inversion Principle Decouple software entities Make software entities reusable
  51. 51. Higher-Order Functions and OO Higher-Order Functions can always be expressed using Objects. Not every expression using Objects is also a Higher-Order Function. I recommend to avoid calling methods that have Methods with side-effects as parameters or return values “Higher-Order Functions”.
  52. 52. Higher-Order Functions References Higher-order function (Wikipedia) How is dependency inversion related to higher-order functions? (StackExchange)
  53. 53. Imperative vs Declarative
  54. 54. Find Even Numbers Double it Sum it up public int calculate() { int[] numbers = {1, 5, 10, 9, 12}; List<Integer> doubledEvenNumbers = new ArrayList<>(); for (int number : numbers) if (number % 2 == 0) doubleEvenNumbers.add(num * 2); int total = 0; for (int even : doubleEvenNumbers) total = total + even; return total; } Imperative Style
  55. 55. Declarative Style val list = List(1, 5, 10, 9, 12) val total = list.filter( number => number % 2 == 0) .map ( evenNumber => evenNumber * 2) .sum
  56. 56. Imperative Paradigm How to do it Mutability Use locking / synchronization for thread safety Side effects null values
  57. 57. Declarative Paradigm What to do Immutability No loops (recursion)
  58. 58. Persistent Data Structures
  59. 59. Get popcorn, lean back, relax and enjoy If you know Git internals
  60. 60. Now listen carefully and learn something about Git at the same time! If you do not know Git internals
  61. 61. “All fields final” - even in data structures. Previous version is preserved. Modifying data structures actually creates copies of modified parts, references of unmodified parts. Persistent Data Structure
  62. 62. Three Levels of Persistence 1.Partially Persistent Query all versions Update only latest version 2.Fully Persistent Query all versions Update all versions 3.Confluently Persistent Combinators -> Directed Acyclic Graph
  63. 63. Immutable (Persistent) Object 1 class Point { 2 final int x; 3 final int y; 4 Point(final int x, final int y) { 5 this.x = x; 6 this.y = y; 7 } 8 }
  64. 64. Persistent Data Structures: List 1 public class ListNode<T> { 2 public final ListNode<T> next; 3 public final T data; 4 public ListNode(final T data) { this(null, data); } 5 public ListNode(final ListNode<T> next, final T data) { 6 this.next = next; 7 this.data = data; 8 } 9 }
  65. 65. Persistent Data Structures: List fedcba
  66. 66. Persistent Data Structures: List fedcba c’b’a’
  67. 67. Persistent Data Structures: Tree 1 public class TreeNode<T> { 2 public final TreeNode<T> left; 3 public final TreeNode<T> right; 4 public final T data; 5 public TreeNode(final T data) {this(null, null, data);} 6 TreeNode(TreeNode<T> left, TreeNode<T> right, T data) { 7 this.left = left; 8 this.right = right; 9 this.data = data; 10 } 11 }
  68. 68. Persistent data structure (Wikipedia) Data Structures (Clojure) Persistent Data Structures References
  69. 69. Lazy Evaluation
  70. 70. Evaluation Strategies Strict Evaluation Non-strict Evaluation
  71. 71. int x = 5 * 3; System.out.println(x); int x = product(2); System.out.println(x); public int product(int num) { System.out.println("product method"); return num * 3; } product method 6
  72. 72. Evaluate immediately at the time of assignment Call By Value Call By Reference Strict Evaluation
  73. 73. multiply(true, 10 / 0); int multiply(boolean flag, int i) { if (flag) return 100; else return i * 5; } // → Division by zero
  74. 74. Non Strict Evaluation
  75. 75. Function parameter assignment Variable assignment 2 types of assignments
  76. 76. val result = product(true, 10/0) println(result) def product(flag: => Boolean, num: => Int) = { if (flag) 100 else 5 * num } // → 100
  77. 77. Call By Name (Function Parameters) Call By Need (Variables) Call By Need = Lazy Evaluation Non Strict Evaluation
  78. 78. public class Singleton { private static Singleton instance = null; private Singleton() {} public static Singleton getInstance() { if (instance == null) { System.out.println("Create new for the first time."); instance = new Singleton(); } return instance; } public static void main(final String... args) { Singleton.getInstance(); Singleton.getInstance(); } }
  79. 79. lazy val result = func("Hello") println("333") println(result) println(result) def func(str: String) = { println("Inside func") str + ", World!" } 333 Inside func Hello, World! Hello, World!
  80. 80. Avoids unnecessary computation → More Performance Evaluates only once → More Performance Infinite Data Structures (Streams) Why Lazy Evaluation?
  81. 81. Lazy Description of Odd Numbers lazy 1 lazy 3 lazy 5 lazy 7 lazy 9 So on … 1 3 5 7 9 So on …
  82. 82. Avoids unnecessary computation → More Performance Infinite Data Structures (Streams) Modularity Why Lazy Evaluation?
  83. 83. Haskell By default Non Strict Evaluation
  84. 84. Partial Functions
  85. 85. 𝑓 : ℕ0 × ℕ0 → ℕ0 𝑓(𝑥, 𝑦) = 𝑥 + 𝑦 Defined ∀ 𝑥: 𝑥 ∊ ℕ0 ⇒ Total Function Partial Functions in Mathematics typedef uint32_t u32; u32 f(u32 x, u32 y) { return x + y; }
  86. 86. 𝑓 : ℕ0 × ℕ0 → ℕ0 𝑓(𝑥, 𝑦) = 𝑥 + 𝑦 Defined ∀ 𝑥: 𝑥 ∊ ℕ0 ⇒ Total Function 𝑓 : ℕ0 × ℕ0 → ℕ0 𝑓(𝑥, 𝑦) = 𝑥 − 𝑦 Only when 𝑥 ≥ 𝑦 ⇒ Partial Function Partial Functions in Mathematics typedef uint32_t u32; u32 f(u32 x, u32 y) { return x + y; } u32 f(u32 x, u32 y) { return x - y; }
  87. 87. Partial Functions in Scala val isEven: PartialFunction[Int, String] = { case x if x % 2 == 0 => x + "is even" } val isOdd: PartialFunction[Int, String] = { case x if x % 2 == 1 => x + "is odd" } val sample = 1 to 10 val evenNumbers = sample collect isEven val numbers = sample map (isEven orElse isOdd)
  88. 88. Partial Functions “You almost never have an excuse for writing a partial function!” - Haskell Wiki
  89. 89. Partial Functions References Partial Function (Wikipedia) Partial Functions (Haskell Wiki) PartialFunction (Scala API)
  90. 90. Function Composition
  91. 91. float x, y, z; y = g(x); z = f(y); z = f(g(x));
  92. 92. “Function Composition” is applying one function to the results of another. Haskell foo = f . g Scala val add = (x: Int) => x + 10 val subtract = (x: Int) => x - 5 List(10, 20, 30).map(add and Then subtract) First Class Composition
  93. 93. Currying
  94. 94. “Currying is similar to the process of calculating a function of multiple variables for some given values on paper.” - Wikipedia Currying
  95. 95. Currying for the poor: Method Overloading class Complex { final double real; final double imaginary; Complex(double real, double imaginary) { this.real = real; this.imaginary = imaginary; } static Complex real(double real) { return new Complex(real, 0); } }
  96. 96. Formal Definition of Currying Given a function f of type f : (X × Y) → Z, currying it makes a function curry(f): X → (Y → Z) That is, curry(f) takes an argument of type X and returns a function of type Y → Z.
  97. 97. Currying in Scala def add(x: Int, y: Int) = x + y add(1, 2) // 3 add(7, 3) // 10 def add(x: Int)(y: Int) = x + y add(1)(2) // 3 add(7)(3) // 10
  98. 98. Currying existing Functions def add(x: Int, y: Int) = x + y val addCurried = Function.curried(add _) add(1, 2) // 3 addCurried(1)(2) // 3
  99. 99. Currying (Wikipedia) Function Currying in Scala (Code Commit) Currying References
  100. 100. Questions? Thank you!
  101. 101. Images used may be subject to copyright. Use in this presentation on the basis of fair use for the purpose of teaching and education. References
  102. 102. Backup Slides follow Not part of the presentation
  103. 103. Reducing the Transformation Priority Premise for Functional Programming Functional Programming and TPP
  104. 104. Original {} → nil nil → constant constant → constant+ constant → scalar statement → statements unconditional → if scalar → array array → container statement → recursion if → while expression → function variable → assignment Transformation Priority Premise Functional {} → nil nil → constant constant → constant+ n/a statement → statements unconditional → if scalar → list n/a statement → recursion n/a (use recursion) expression → function n/a
  105. 105. More Examples
  106. 106. main(Argv) :- echo(Argv). echo([]) :- nl. echo([Last]) :- write(Last), echo([]). echo([H|T]) :- write(H), write(' '), echo(T). Echo in Prolog
  107. 107. qsort :: (Ord a) => [a] -> [a] qsort [] = [] qsort (x:xs) = let left = qsort [a | a <- xs, a <= x] right = qsort [a | a <- xs, a > x] in left ++ [x] ++ right --or even shorter qsort (x:xs) = qsort [a | a <- xs, a <= x] ++ [x] ++ qsort [a | a <- xs, a > x] Quicksort in Haskell
  108. 108. Quicksort in Perl 5 sub qsort { return @_ if @_ < 2; my $p = splice @_, int rand @_, 1; qsort(grep$_<$p,@_), $p, qsort(grep$_>=$p,@_); }
  109. 109. Quicksort in Scala def qsort[T](list: List[T])(implicit ev1: T => Ordered[T]): List[T] = list match { case Nil => Nil case p :: xs => val (lesser, greater) = xs partition (_ <= p) qsort(lesser) ++ List(p) ++ qsort(greater) }
  110. 110. Alternate and Extended Slides
  111. 111. f(x) = 2x2 - 2x + 3
  112. 112. f(x) = 2x2 - 2x + 3 f(4) = 2*4*4 - 2*4 + 3 = 32 - 14 + 3 = 27 The value of x will never change inside a mathematical function. Same input, same output - all the time! Call f() multiple times, without any side-effects. We don’t have to recalculate f(4), replace occurrence of f(4) with 27 (Referential Transparency)
  113. 113. public class Account { int balance; public Account(int balance) { this.balance = balance; } public int credit(int amount) { return balance += amount; } } Account account = new Account(100); account.credit(500); // → balance == 600 account.credit(500); // → balance == 1100
  114. 114. public class Account { final int balance; public Account(int balance) { this.balance = balance; } public Account credit(int amount) { return new Account(balance + amount); } } Account account = new Account(100); Account currentAccountState = account.credit(500); Account newAccountState = currentAccountState.credit(500); account.credit(500); // → currentAccount(600)
  115. 115. public int calculate() { int[] numbers = {1, 5, 10, 9, 12}; List<Integer> doubledEvenNumbers = new ArrayList<>(); int total = c; for (int number : numbers) if (number % 2 == 0) total += num * 2; return total; } Imperative Style
  116. 116. Declarative Style public int calculate() { return IntStream.of(1, 5, 10, 9, 12) .filter(number -> number % 2 == 0) .map(number -> number * 2) .sum(); }
  117. 117. Declarative Style def calculate() { List(1, 5, 10, 9, 12) .filter(number => number % 2 == 0) .map(number => number * 2) .sum }
  118. 118. public int product(int num) { System.out.println("product method"); return num * 3; } int x = 5 * 3; System.out.println(x); x = product(2); System.out.println(x); 15 product method 6
  119. 119. int multiply(boolean flag, int i) { if (flag) return 100; else return i * 5; } System.out.println(multiply(true, 10 / 0)); // → Division by zero
  120. 120. public class Singleton { private Singleton() { System.out.println("Create new for the first time."); } public static Singleton getInstance() { return LazyHolder.INSTANCE; } private static class LazyHolder { private static final Singleton INSTANCE = new Singleton(); } }
  121. 121. public class Singleton { public static final Singleton INSTANCE = new Singleton(); private Singleton() { System.out.println("Init"); } }
  122. 122. public enum Singleton { INSTANCE; private Singleton() { System.out.println("Init"); } }

×