Upload
phamhuong
View
222
Download
0
Embed Size (px)
Citation preview
λUvod u funkcijsko programiranje
Dinko Srkoč, Helix d.o.o.
Lambda
Haskell
Clojure
Racket
Philip WadlerFaith, Evolution, and Programming LanguagesQCon 2012
Abelson, SussmanSICP, 2. izdanjeThe MIT Press
Izvori:http://mitpress.mit.edu/sicp/full-text/book/book.htmlhttp://www.infoq.com/presentations/Faith-Evolution-Programming-Languages
λ - počeci računarstva
Povijest
● 1936 - netipizirani λ račun
● 1940 - tipizirani λ račun
Alonzo Church (1903 - 1995)Izvor: http://en.wikipedia.org/wiki/File:Alonzo_Church.jpg
Povijest - λ-računformalni sustav za ispitivanje definicije i aplikacije funkcije te za definiranje izračunljive funkcije
λ-račun je ekvivalentan univerzalnom Turingovom stroju
funkcijski jezici kao razrada λ-računa Alonzo Church (1903 - 1995)
Povijest - λ-račun
λx.t ↔ f(x) = t
Alonzo Church (1903 - 1995)
Imperativno programiranje
Niz naredbi (eng. statement) koje mijenjaju stanje programa.
● mijenjanje vrijednosti varijabli● korištenje pridruživanja● kontrolne strukture - if-then-else, petlje,
break, continue, ...
Što je funkcijsko programiranje?
● u ograničenom smislu:programiranje bez promjenjivih varijabli, pridruživanja, petlji, ...
● u proširenom smislu:programiranje koristeći funkcije
Martin Odersky, Functional Programming Principles in Scala, Coursera.org
Što je funkcijski programski jezik?
● u ograničenom smislu:programski jezik koji ne podržava promjenu vrijednosti varijabli, pridruživanja ili imperativne kontrolne strukture
● u proširenom smislu:programski jezik koji olakšava rad s funkcijama
Martin Odersky, Functional Programming Principles in Scala, Coursera.org
Funkcijski programski jezici
● Haskell● Standard ML, Ocaml, F#● Lisp, Scheme, Racket, Clojure*● Scala*● Groovy*, Ruby, Smalltalk, JavaScript
(*) jezici rađeni za JVM
Usporedba:funkcijski ↔ imperativno
funkcijsko programiranje
opisuje računanje kao evaluaciju matematičkih funkcija
što treba napraviti
imperativno programiranje
opisuje računanje kao niz naredbi koje mijenjaju stanje programa
kako treba nešto napraviti
Primjeri
Talk is cheap. Show me the code.
Linus Torvalds
Izvor: http://en.wikipedia.org/wiki/File:Linus_Torvalds.jpeg
Primjer 1
Funkcija za računanje faktorijela
n! = n * (n - 1) * (n - 2) * ... * 1
Primjer 1
Funkcija za računanje faktorijela
// n! = n * (n - 1) * ... * 1public long factorial(long n) { long res = 1; for (long i = n; i > 0; i--) { res = res * i; } return res;}
Java
Primjer 1 - rekurzija
Funkcija za računanje faktorijela
// n! = n * (n - 1) * ... * 1public long factorialR(long n) { if (n == 1) return 1; else return n * factorialR(n - 1);}
Java
Primjer 1 - rekurzija
Funkcija za računanje faktorijela
// n! = n * (n - 1) * ... * 1public long factorialR(long n) { if (n == 1) return 1; else return n * factorialR(n - 1);}
Java
● algoritam bliži matematičkom izrazu
● nema pridruživanja, promjenjivih vrijednosti
● java.lang.StackOverflowError
Primjer 1 - rekurzija
Funkcija za računanje faktorijela
// n! = n * (n - 1) * ... * 1def factorial(n: Long): Long = if (n == 1) 1 else n * factorial(n - 1)
Scala
još uvijekjava.lang.StackOverflowError!
Primjer 1 - rekurzija
Funkcija za računanje faktorijela
// n! = n * (n - 1) * ... * 1def factorial(n: Long): Long = { @scala.annotation.tailrec def iter(n: Long, acc: Long):Long= if (n == 1) acc else iter(n - 1, n * acc)
iter(n, 1)}
Scala
Tail Call Optimization
Rekurzija
Recursion is the root of computation since it trades description for time
Alan J. Perlis (1922 - 1990)
To iterate is human, to recurse divine
L Peter Deutsch (1946)
Izvori:http://amturing.acm.org/photo/perlis_0132439.cfmhttp://www.vintage.org/2003/main/bio.php?id=54&back=37
Primjer 2
Broj slova u popisu imena
public List<Integer> lengths(List<String> names) { List<Integer> res = new ArrayList<>(); for (String name : names) { res.add(name.length()); } return res;}
Java
Primjer 2
Broj slova u popisu imena
def lengths(names: List[String]): List[Int] = if (names.isEmpty) List() else names.head.length :: lengths(names.tail)
Scala
Primjer 2
Broj slova u popisu imena
def lengths(names) { names.collect { name -> name.size() }}
Groovy
Primjer 2 - funkcije
Broj slova u popisu imenaGroovy
def lengths = { name -> name.size()}
names.collect(lengths)
Groovy
● funkcija kao građanin prvog reda
● funkcije višeg reda
Primjer 2 - funkcije
Groovy
def upper = { name -> name.toUpperCase()}
names.collect(upper)
Groovy
● funkcija kao građanin prvog reda
● funkcije višeg reda
Funkcije višega reda
// map, collect, selectdef map[A, B](xs: List[A], f: A ⇒ B): List[B]
// filter, findAll, wheredef filter[A](xs: List[A], f: A ⇒ Boolean): List[A]
// foldLeft, reduce, injectdef foldLeft[A, B](xs: List[A], z: B, f: (B,A) ⇒ B): B
Scala
Funkcije višega reda
// map, collect, selectList(1, 2, 3) map { x ⇒ x * x } // ... List(1, 4, 9)
// filter, findAll, where1 to 10 filter (_ % 2 == 0) // ... Vector(2, 4, 6, 8, 10)
// foldLeft, reduce, injectList(1, 2, 3).foldLeft(0) { (acc, x) ⇒ acc + x } // ... 6
Scala
Primjeri
Closure
Groovy
def add(x) { { y -> x + y }}
def add5 = add(5) // { y -> x + y }
add5(10) // vraća 15
Groovy
Closure
Groovy
def add(x) { { y -> x + y }}
def add5 = add(5) // { y -> x + y }
add5(10) // vraća 15
Groovy
● x unutar leksičkog dosega● closure = funkcija + okolina
Kompozicija - f ∘ g(f ∘ g)(x) = f(g(x))
def longest = { strs -> strs.inject { max, s -> max.size() > s.size() ? max : s}}def capitals = { strs -> strs.findAll { it == it.capitalize() }}def strToList = { str -> str.tokenize() }
def longestCapital = longest << capitals << strToList
longestCapital 'Bratac Jaglenac i sestrica Rutvica'// vraća 'Jaglenac'
Groovy
Currying (Schönfinkeling)transformacija funkcije koja prima višestruke argumente u niz funkcija s jednim argumentom
// opsegTrokuta: (Int, Int, Int) ⇒ Intval opsegTrokuta=(a: Int, b: Int, c: Int) ⇒ a + b + c
// cOpseg: Int ⇒ (Int ⇒ (Int ⇒ Int))val cOpseg = opsegTrokuta.curried
val o1 = cOpseg(1) // o1: Int ⇒ (Int ⇒ Int)val o2 = o1(2) // o2: Int ⇒ Intval o3 = o2(3) // o3: Int, o3 == 6// opsegTrokuta(1, 2, 3)
Scala
Haskell Curry (1900 - 1982)Izvor: http://www.apprendre-math.info/history/photos/Curry.
jpeg
The Good, the Bad and ...
● bez nuspojava - lakše razumjeti i predvidjeti ponašanje programa
● bez mutirajućih varijabli - lakši paralelni rad
● deklarativni kôd - često kraći i razumljiviji
● funkcijski jezici su često manje efikasni
● "drugačija" programska paradigma
● rekurzija i StackOverflowError
PonovimoFunkcijsko programiranje:● bez promjenjivih varijabli● upotreba čistih funkcija
Značajke:● petlja → rekurzija● deklarativni stil● funkcije kao vrijednosti i funkcije višeg reda
Još malo citataThe way we can tell it's C# instead of Haskell is because it's nine lines instead of two.
Philip Wadler
A monad is a monoid in the category of endofunctors, what's the problem?
James Iry (kvazi-citirao Wadlera)
Remember, kids: if you program in a language with side effects, the terrorists win.
Tommah (Haskell Weekly News, 7.5.2007)
Pitanja
?Hvala na pažnji