Functional programming

133
Functional Programming ExperTalks 2015-09-11 Leena Bora, Equal Experts Christian Hujer, Nelkinda Software Craft

Transcript of Functional programming

Functional ProgrammingExperTalks 2015-09-11Leena Bora, Equal ExpertsChristian Hujer, Nelkinda Software Craft

Christian Hujer () - I personally would first show the graph, then talk about the details...Christian Hujer () - Changed sequence to1. Method2. Call3. Output (New!)Christian Hujer () - I changed this and the next slide to use the identical formula, and I tweaked the styling a bit.Flying to other stars

Methods that dont work

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

Can we break the speed limit?Sci-Fi authors: Yes

Scientists: No!

Miguel Alcubierre from Mexico

watched Star Trek TNG

and then had the idea for this:

ds2 = -(2 - i i) dt2 + 2i dxi dt + ij dxidxj

which I dont really understand,

but if it works...

it would allow this

Further InformationAlcubierre Drive (Wikipedia)Miguel Alcubierre (Wikipedia)The warp drive: hyper-fast travel within general relativity - Miguel Alcubierre, 1994Warp Drive (Wikipedia)RF resonant cavity thruster (Wikipedia)

History ofFunctional Programming

1903 - 19951930s calculus1936untyped calculus1940simple typed calculus

Alonzo Church: Lambda-Calculus

John McCarthy: Lisp1927 - 20111958Lisp1959Garbage Collection1961Utility Computing(Cloud!)1971Turing Award

John Backus

1924 - 20071957FORTRAN1960Backus-Naur-Form1977Turing Award, FPCan Programming be Liberated from the von Neumann Style?

Milestones1936 Lambda Calculus (Church & Rosser)1958 Lisp (McCarthy)1963 Algol 60 (Naur et al)1966 ISWIM (Landin)1969 NPL, ML, HOPE1973 SASL1986 Miranda1992 Haskell2007 Clojure2013 Java 8

Moores Law (1965)Gordon E. Moore*1929Co-founder of Intel

~ Number of transistors doubles every 18 months More GHzBut for how long?

Amdahls Law (1967)Gene Amdahl*1922IBM MainframesAmdahl Corporation

Amdahls LawGiven , the number of threads of executionB [0, 1], strictly serial fraction of algorithmTime T() it takes to finish with n threads isT() = T(1)(B + 1/ (1 B))Therefore, the theoretical speedup S() isS() = T(1) / T() = 1 / (B + 1/ (1 - B))

Gustafsons LawJohn Gustafson*1955HPCComputer Clusters

Gustafsons LawGiven a the sequential time, b the parallel time, P the number of processors,a + b single thread timea + P b sequential time(a + P b) / (a + b) speedup = a / (a + b)sequential fraction S(P):S(P) = + P (1 ) = P (P 1)

To run fastParallelismAvoid Race conditions

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)Moores Law (Wikipedia)Gene Amdahl (Wikipedia)Amdahls Law (Wikipedia)John Gustafson (Wikipedia)Gustafsons Law (Wikipedia)History of Functional ProgrammingReferences

Programming Paradigm

It is all about functionsWhat is Functional Programming?

f(x) = 2x + 3f(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 dont have to recalculate f(2), replace occurrence of f(2) with 7 (Referential Transparency)

f(x) = 2x 2x + 3

Pure Functionpublic int calculate(int x) { return (2 * x) + 3;}

calculate(2) = 7

calculate(2) = 7

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

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)

Christian Hujer () - I think account is not a good example. When you refer to an account elsewhere, you would actually WANT that when money is credited, that it is reflected. Using functional programming for Account would be plain wrong, I fear. Besides, non-persistent accounts would probably not make any sense. Using functional programming for a class like Account is very likely to violate referential integrity of object-oriented programs. Can we use something like Point instead of Account for this example? Something like Point, or Date, would have the advantage that immutability and functional programming support, not contradict, the referential integrity of object-oriented programs and we could demonstrate better that OOP and FP do not need to contradict.Modifying global variable / data structureModifying input valueThrowing an exceptionRead / Write (File, Console, Database)Communication with External SystemSide Effects

Thin layer of impure functions(DB, I/O, exceptions)Pure functions at the core

Why Pure Functions?No Side-effectsA function f is said to be a pure function if f(x) is referentially transparentMemoizationExecution Order can be rearranged (!)Local ReasoningParallel Executionpublic int square (int number) { return number * number;}

Functional Programming is so calledbecause a program consists ofpure functions & functions

Where FP and OOP meet for the DIPHigher-Order Functions

No function as argument,and no function as return

First-Order vs Higher-OrderFunction as argument,or function as return(or both)

Workarounds if unavailableFunction Pointer TypesFunction Pointers

One-Element InterfacesObjects

1 #include // qsort 2 #include // 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 CExample: qsort()

1 enum AccountComparator implements Comparator { 2 INSTANCE; 3 public int compare(Account a1, Account a2) { 4 return Integer.compare(a1.balance, a2.balance); 5 } 6 } 7 8 List accounts = ; 9 accounts.sort(AccountComparator.INSTANCE);Higher-Order Functions in JavaExample: List.sort()

Method ReferencesLambda Expressions

Syntactic sugar for higher-order functions.Underneath: generated anonymous classes.Improvements in Java 8

1 class Account { 2 int balance; 3 Account(int balance) { this.balance = balance; } 4 public static final Comparator BY_BALANCE = 5 new Comparator() { 6 public int compare(Account a1, Account a2) { 7 return compare(a1.balance, a2.balance); 8 } 9 };10 }11 12 List accounts;13 accounts.sort(BY_BALANCE);Java 5 Anonymous Class

1 class Account { 2 int balance; 3 Account(int balance) { this.balance = balance; } 4 public static final Comparator BY_BALANCE = 5 6 ( a1, a2) -> { 7 return compare(a1.balance, a2.balance); 8 } 9 ;10 }11 12 List accounts;13 accounts.sort(BY_BALANCE);Java 8 Block Lambda

1 class Account { 2 int balance; 3 Account(int balance) { this.balance = balance; } 4 public static final Comparator BY_BALANCE = 5 6 ( a1, a2) -> 7 compare(a1.balance, a2.balance) 8 9 ;10 }11 12 List accounts;13 accounts.sort(BY_BALANCE);Java 8 Expression Lambda

1 class Account { 2 int balance; 3 Account(int balance) { this.balance = balance; } 4 public static final Comparator BY_BALANCE = 5 (a1, a2) -> compare(a1.balance, a2.balance); 6 } 7 8 List accounts; 9 accounts.sort(BY_BALANCE);Java 8 Expression Lambda

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 CallbackJava 5 Anonymous Class

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 CallbackJava 8 Expression Lambda

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 }

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 }

What if you want to reuse A without B?Dependency Inversion PrincipleComponent AComponent B

What if you want to reuse A without B?Dependency Inversion PrincipleComponent AComponent BSortArticle

What if you want to reuse A without B?Dependency Inversion PrincipleComponent AComponent BSortArticleComparable

Higher Order FunctionsAre a form of polymorphismServe the Dependency Inversion PrincipleDecouple software entitiesMake software entities reusable

Higher-Order Functions and OOHigher-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.

Higher-Order FunctionsReferencesHigher-order function (Wikipedia)How is dependency inversion related to higher-order functions? (StackExchange)

Imperative vs Declarative

Find Even NumbersDouble itSum it uppublic int calculate() { int[] numbers = {1, 5, 10, 9, 12}; List 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

Declarative Style

val list = List(1, 5, 10, 9, 12)

val total = list.filter( number => number % 2 == 0) .map ( evenNumber => evenNumber * 2) .sum

Imperative ParadigmHow to do itMutabilityUse locking / synchronization for thread safetySide effectsnull values

Declarative ParadigmWhat to doImmutabilityNo loops (recursion)

Christian Hujer () - You could mention implicit thread-safety due to the lack of side-effects.Christian Hujer () - Declarative Programming does not imply immutability. SQL is a declarative language, and SQL data is not immutable. Also, Prolog is a declarative programming language, but not everything in Prolog is immutable.Persistent Data Structures

Get popcorn, lean back, relax and enjoyIf you knowGit internals

Now listen carefully and learn something about Git at the same time!If you do not knowGit internals

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

Three Levels of PersistencePartially PersistentQuery all versionsUpdate only latest version

Fully PersistentQuery all versionsUpdate all versions

Confluently PersistentCombinators -> Directed Acyclic Graph

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 }

Persistent Data Structures: List 1 public class ListNode { 2 public final ListNode next; 3 public final T data; 4 public ListNode(final T data) { this(null, data); } 5 public ListNode(final ListNode next, final T data) { 6 this.next = next; 7 this.data = data; 8 } 9 }

Persistent Data Structures: Listfedcba

Persistent Data Structures: Listfedcbacba

Persistent Data Structures: Tree 1 public class TreeNode { 2 public final TreeNode left; 3 public final TreeNode right; 4 public final T data; 5 public TreeNode(final T data) {this(null, null, data);} 6 TreeNode(TreeNode left, TreeNode right, T data) { 7 this.left = left; 8 this.right = right; 9 this.data = data;10 }11 }

Persistent data structure (Wikipedia)Data Structures (Clojure)Persistent Data StructuresReferences

Lazy Evaluation

Evaluation Strategies

Strict EvaluationNon-strict Evaluation

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 method6

Evaluate immediately at the time of assignment

Call By ValueCall By ReferenceStrict Evaluation

multiply(true, 10 / 0);

int multiply(boolean flag, int i) { if (flag) return 100; else return i * 5;}

// Division by zero

Non Strict Evaluation

Function parameter assignmentVariable assignment

2 types of assignments

val result = product(true, 10/0)println(result)

def product(flag: => Boolean, num: => Int) = { if (flag) 100 else 5 * num}

// 100

Call By Name (Function Parameters)Call By Need (Variables) Call By Need = Lazy Evaluation

Non Strict Evaluation

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(); }}

Christian Hujer () - I don't like this example for several reasons:1. The print should actually be done in the constructor so a change to the code wouldn't lead to the print not happening (maintainability).2. Your original version was not thread-safe. I have added synchronized for that, however that's actually NOT how a skilled Java developer would do it. It would be this way:public class Singleton { private Singleton() {} public static Singleton getInstance() { return LazyHolder.INSTANCE; } private static class LazyHolder { private static final Singleton INSTANCE = new Singleton(); }}3. Singletons are evil anyway.4. The lazy initialization is not necessary because Java loads and initializes classes upon first use.5. Nowadays if I really need a SIngleton, I'd use an enum.lazy val result = func("Hello")

println("333")println(result)println(result)

def func(str: String) = { println("Inside func") str + ", World!"}

333Inside funcHello, World!Hello, World!

Avoids unnecessary computation More Performance

Evaluates only once More Performance

Infinite Data Structures (Streams)

Why Lazy Evaluation?

Lazy Descriptionof Odd Numbers

lazy 1lazy 3lazy 5lazy 7lazy 9So on

13579So on

Avoids unnecessary computation More Performance

Infinite Data Structures (Streams)

ModularityWhy Lazy Evaluation?

HaskellBy default Non Strict Evaluation

Partial Functions

: 0 0 0(, ) = + Defined : 0 Total FunctionPartial Functions in Mathematicstypedef uint32_t u32;

u32 f(u32 x, u32 y){ return x + y;}

: 0 0 0(, ) = + Defined : 0 Total Function

: 0 0 0(, ) = Only when Partial FunctionPartial Functions in Mathematicstypedef uint32_t u32;

u32 f(u32 x, u32 y){ return x + y;}

u32 f(u32 x, u32 y){ return x - y;}

Partial Functions in Scalaval 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 10val evenNumbers = sample collect isEvenval numbers = sample map (isEven orElse isOdd)

Partial FunctionsYou almost never have an excuse for writing a partial function! - Haskell Wiki

Partial FunctionsReferencesPartial Function (Wikipedia)Partial Functions (Haskell Wiki)PartialFunction (Scala API)

Function Composition

float x, y, z;y = g(x);z = f(y);

z = f(g(x));

Function Composition is applying one function to the results of another.

Haskellfoo = f . g

Scalaval add = (x: Int) => x + 10val subtract = (x: Int) => x - 5

List(10, 20, 30).map(add and Then subtract)First Class Composition

Currying

Currying is similar to the process of calculating a function of multiple variables for some given values on paper. - WikipediaCurrying

Currying for the poor:Method Overloadingclass 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); }}

Formal Definition of CurryingGiven a function f of type f : (X Y) Z, currying it makes a functioncurry(f): X (Y Z)

That is, curry(f) takes an argument of type X and returns a function of type Y Z.

Currying in Scaladef add(x: Int, y: Int) = x + y

add(1, 2) // 3add(7, 3) // 10

def add(x: Int)(y: Int) = x + y

add(1)(2) // 3add(7)(3) // 10

Currying existing Functionsdef add(x: Int, y: Int) = x + yval addCurried = Function.curried(add _)

add(1, 2) // 3addCurried(1)(2) // 3

Currying (Wikipedia)Function Currying in Scala (Code Commit)CurryingReferences

Questions?Thank you!

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

Backup Slides followNot part of the presentation

Reducing the Transformation Priority Premise for Functional ProgrammingFunctional Programming and TPP

Original{} nilnil constantconstant constant+constant scalarstatement statementsunconditional ifscalar arrayarray containerstatement recursionif whileexpression functionvariable assignment

Transformation Priority PremiseFunctional{} nilnil constantconstant constant+n/astatement statementsunconditional ifscalar listn/astatement recursionn/a (use recursion)expression functionn/a

More Examples

main(Argv) :- echo(Argv).

echo([]) :- nl.echo([Last]) :- write(Last), echo([]).echo([H|T]) :- write(H), write(' '), echo(T).Echo in Prolog

qsort :: (Ord a) => [a] -> [a]qsort [] = []qsort (x:xs) = let left = qsort [a | a number * 2) .sum();}

Christian Hujer () - I fear that this is wrongly called declarative. The code is still telling what to do. Declarative would be even more abstract. GNU make or Prolog are somewhat declarative in nature. Using annotations in Java is declarative. While this code is functional, I doubt whether declarative is the correct academic / scientific term here.Christian Hujer () - I inserted the Java example. That way I think it becomes much more obvious that the achieved brevity is due to functional programming paradigm, not due to the programming language Scala vs Java.I intentionally kept the font size the same, although it could be bigger on this slide, so one can see how much less code it is.Declarative Styledef calculate() { List(1, 5, 10, 9, 12) .filter(number => number % 2 == 0) .map(number => number * 2) .sum}

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);

15product method6

int multiply(boolean flag, int i) { if (flag) return 100; else return i * 5;}

System.out.println(multiply(true, 10 / 0));

// Division by zero

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(); }}

Christian Hujer () - This is how Singletons should be done when lazy initialization cannot rely on the ClassLoader.It fails if the initialization throws an exception. However,since you're going to claim exceptions are not FP, that is a weak argument ;)public class Singleton { public static final Singleton INSTANCE = new Singleton(); private Singleton() { System.out.println("Init"); }}

Christian Hujer () - This is actually sufficient in 99% of the cases because the Java ClassLoader already behaves lazily. Class Singleton is only loaded when it's used.public enum Singleton { INSTANCE; private Singleton() { System.out.println("Init"); }}

Christian Hujer () - This is how to do a Singleton in Java properly these days.But don't forget, SIngletons are evil.