Slideshare uses cookies to improve functionality and performance, and to provide you with relevant advertising. If you continue browsing the site, you agree to the use of cookies on this website. See our User Agreement and Privacy Policy.

Slideshare uses cookies to improve functionality and performance, and to provide you with relevant advertising. If you continue browsing the site, you agree to the use of cookies on this website. See our Privacy Policy and User Agreement for details.

Like this presentation? Why not share!

1,042 views

Published on

What the title says. Presented at Timisoara Ruby Community Event. Hosten by UnifiedPost Romania.

Published in:
Technology

No Downloads

Total views

1,042

On SlideShare

0

From Embeds

0

Number of Embeds

7

Shares

0

Downloads

14

Comments

0

Likes

2

No embeds

No notes for slide

- 1. Functional Programming in RubyKoen HandekynCEO
- 2. Learning FPit’s (sometimes) (a bit) difﬁcult (in the beginning) - you need to retrain your brain - but rewarding it’s fun & productive
- 3. History‣ Lambda calculus: 1930’s (Alonzo Church)‣ Lisp: 1950’s, multi-paradigm language strongly inspired by lambda-calculus (symbolic manipulation, rewriting)‣ ML-family: 1970’s, general purpose functional programming language with type inference‣ Haskell: 1987, 1998, 2010, open standard for functional programming research‣ Other: Clean, F#, Scheme, Scala, Clojure, XSLT, Erlang, SQL, ...
- 4. Isn’t all programming functional?‣ FP proceeds from a startling premise—that we construct programs using only pure functions, or functions that avoid side effects like changing variables(state), writing to a database or reading from a ﬁle.‣ In a pure functional programming language, everything is a function. we can pass them around and “calculate” with them (combine, evaluate or partially evaluate, etc).‣ A function deﬁnes a mapping from a “Domain” into the “Codomain” (image, range)
- 5. Advantages‣ No mutable data and hence:‣ No side effects, no implicit hidden state, less bugs.‣ No variables ! (only values) => optimizations‣ Can (more easily) be parallelized over cpu’s (multicore), etc. => no locks, no race conditions, no deadlocks‣ Enables Provability (both for humans and computers)
- 6. FP vs OO‣ Whereas an object-oriented mindset will foster the approach of deﬁning an application domain as a set of nouns (classes) [ person, ticket, etc ]‣ The functional mind will see the solution as the composition or verbs (functions) [ register, sell ]‣ Though both programmers may in all likelihood generate equivalent results, the functional solution will be more succinct, understandable, and reusable. Grand claims indeed!
- 7. Immutable Objects‣ An OO pattern that actually originates in FP world‣ ISO changing a data structure, don’t modify in place but create a new object.‣ In Ruby this is typically the default. Methods that don’t follow this principle are assumed ‘dangerous’ and are typically marked with a ‘!’ • name.reverse => returns a new string that contains the reversed name • name.reverse! => replaces the name with the reversed value
- 8. Ruby and FP‣ Ruby is an imperative and OO language with closure support‣ But we can apply (some) FP principles‣ It allows to mix and match OO with FP programming style A bit of pattern matching‣ You can’t assume immutability ... it’s a choice • x, *xs = [1,2,3,4]‣ No (real) pattern matching (yet) x => 1 xs => [2,3,4]‣ No lazy evaluation (yet) • a,b,tail = [1,2,3,4] a => 1 b => 2 tail => [3,4]
- 9. Recursion# fibonacci functional through recursiondef fib(count, a = 1, b = 1 , r = []) r is the accumulator count == 0 ? r : fib(count-1, b, a+b, r << a)endfib(10) # => [1,1,2,3,5,... needs a bit of practice but once you get it ...
- 10. or also - As opposed to ?‣ Another look at it is to compare imperative programming languages with declarative programming languages‣ Imperative = emphasize on how something is computed‣ Declarative = emphasize on what is to be computed and not on how‣ Imperative is counterintuitive when you’re used to imperative programming
- 11. Taking a look at <<Enumerable >>
- 12. First introduce Closure‣ Closure = an anonymous function block together with a referencing environment‣ Where? javascript, python, ruby, PHP, C# 2.0, java 8! :)
- 13. Enumerable#select(1..10).select { |x| x.odd? } => [1, 3, 5, 7, 9]# imperative styleodds = [](1..10).each do |n| odds << n if n.odd?end
- 14. Enumerable#partition(1..10).partition { |x| x.odd? } => [[1, 3, 5, 7, 9], [2, 4, 6, 8, 10]]# imperative stylep = [[],[]](1..10).each do |n| p[0] << n if n.odd? p[1] << n unless n.odd?end
- 15. Enumerable#map(1..10).map { |x| x * 2 } => [2, 4, 6, 8, 10, 12, 14, 16, 18, 20]# imperative styledoubles = [](1..10).each do |n| doubles << n*2end
- 16. inject & reduce & foldl & foldr
- 17. foldl & foldr
- 18. Enumerable#reduce(1..10).reduce { |x,y| x + y } # repeat sum=> 55# imperative stylesum = 0(1..10).each do |n| sum += nendsum # => 55
- 19. Enumerable#reduce# repeat sum, start with 0(1..10).reduce(0) { |x,y| x + y }=> 55# repeat multiply, start with 1(1..10).reduce(1) { |x,y| x * y }=> 3628800# or ‘for real’ :)(1..10).inject(:+) => 55(1..10).inject(:*) => 3628800
- 20. Enumerator#group_by(1..6).group_by { |i| i%3 }=> {0=>[3, 6], 1=>[1, 4], 2=>[2, 5]}# imperative stylep = {}(1..6).each do |n| k = n%3 p[k] ||= [] p[k] << nend
- 21. Enumerable#sort%w(rhea kea flea).sort#=> ["flea", "kea", "rhea"](1..10).sort {|a,b| b <=> a}#=> [10, 9, 8, 7, 6, 5, 4, 3, 2, 1]# imperative style# ... have fun ...
- 22. (: take a breath :)
- 23. Currying‣ In mathematics and computer science, currying is the technique of transforming a function that takes multiple arguments (or a tuple of arguments) in such a way that it can be called as a chain of functions, each with a single argument (partial application). It was originated by Moses Schönﬁnkel and later re-discovered by Haskell Curry.‣ curry(int, int => bool) = int => (int => bool)
- 24. Functions as Values in Rubyinc = lambda { |x| x + 1 }inc = ->(x) { x + 1 }inc.(4) => 5add = lambda { |x,y| x + y }add = ->(x,y) { x + y }add.(2,3) => 5
- 25. Constants are Functionsconstant = ->(c,x) { c }.curryhello = constant.(“hello”)hello.(1) => “hello”hello.(“eugen”) => “hello”
- 26. Compositionidentity = ->(x) { x } # a closurepower = ->(base, x) { base**x }.currysum_of = ->(f, xs, i=0) { xs.inject(i) { |a,i| a+=f.(i) } }.currysum_of_numbers = sum_of.(identity) a Higher Ordersum_of_power2s = sum_of.(power.(2)) function takes asum_of_squares = sum_of.(square) function as parameter# usagesum_of_numbers.(0..10) # => 55sum_of_squares.(0..10) # => 2047sum_of.( power.(3) ).(0..10) # => 88573
- 27. Constants are Functionsconstant = ->(c,x) { c }.currysum_of = ->(f, r, i=0) { r.inject(i) { |a,i| a+=f.(i) } }.curryword_count = sum_of.( constant.(1) )word_count.( %w(welcome to the world of fp) ) => 6
- 28. Currying and Partial Evaluationpower = ->(base, x) { base**x }.currypower.(10,2) # => 100power.(10).(2) # => 100power2 = power.(2) # partial evaluationpower2.(3) # => 8add = ->(x,y) { x + y }.curryadd.(2,3) => 5inc = add.(1) # partial evaluationinc.(3) => 4
- 29. Currying and Partial Evaluation# meta functional programming ;)send = ->(m, o) { o.send(m) }.currylength_of = send.(:length)length_of.(“koen”) # => 4length_of.([12,4,25,32,[2,2]]) # => 5
- 30. More Composition# from previouslength_of = ->(o) { o.length }sum_of = ->(f, r, i=0) { r.inject(i) { |a,i| a+=f.(i) } }.curry# composetotal_length_off = sum_of.(length_of)# usetotal_length_off.( [koen,ciprian,eugen] ) # => 16total_length_off.( [ [2,3,4], "koen", [3,4,5] ] ) # => 10
- 31. Playing with boxesbox1 = { width: 230, heigth: 304 }box2 = { width: 340, heigth: 243 }by_key = ->(k, o) { o[k] }.curryby_width = by_key.(:width)taller = ->(f, a, b) { f.(a) > f.(b) }.currytaller.(by_width, box1, box2) # => falsetaller.(by_key.(:heigth)).(box1,box2) # => true
- 32. More boxescompose = ->(f,g,x) { g.(f.(x)) }.currysquare = ->(x) { x*x }square_width = compose.(by_width).(square)square_width.(box1) # => 52900square_height = compose.(by_key.(:heigth)).(square)square_height.(box1) # => 92416
- 33. More compositionmap = ->(f, a) { a.map { |x| f.(x) }}.curry # turn method into lambdasquares = ->(a) { map.(square).(a) }squares = map.(square) # nicer through composition, not ? :)sum = ->(a) { a.inject(0,:+) }square_of_sum = compose.(sum).(square)after = composesum_of_squares = after.(squares).(sum)square_of_sum.([2,3]) # => 25sum_of_squares.([2,3]) # => 13square_of_sum.([2,3,4]) # => 81sum_of_squares.([2,3,4]) # => 29
- 34. More compositionbook = [ %w(this is a long sentence), %w(this is a short), %w(yes) ]foldl = ->(f, arr) { arr.inject { |r, x| f.(r, x) } }.curryadd = ->(a,b) { a+b }div = ->(a,b) { a*1.0/b }length = ->(x) { x.length }sum = foldl.(add)divide = foldl.(div)pair = parallel = ->(f,g,x) { [f.(x), g.(x) ] }.curryaverage = ->(a) { sum.(a) / length.(a) }average = after.( pair.(sum).(length) ).(divide)average_wordcount = after.( map.(length) ).(average) # => 3.33
- 35. More Compositionbook = [ %w(this is a long sentence), %w(this is a short), %w(yes) ]flatten = ->(arr) { arr.flatten } # convert to lambdawordlengths = after.( flatten ).( map.(length) )average_wordlength = after.(wordlengths).(average)average_wordlength.(book) # => 3.4
- 36. Liquer Storesliquer_stores = []liquer_stores << { name: "total", d: 2.0, price: 32.0 }liquer_stores << { name: "shell", d: 2.6, price: 28.5 }liquer_stores << { name: "esso", d: 3.2, price: 41.0 }liquer_stores << { name: "q8", d: 3.5, price: 22.0 }liquer_stores << { name: "shell", d: 4.5, price: 19.0 }liquer_stores << { name: "q8", d: 5.5, price: 18.0 }
- 37. Imperative Liquerdef cheap_boose_nearby (liquer_stores) min = liquer_stores[0][:price] liquer_stores.each do |store| if store[:d] < 5.0 then price = store[:price] price = price * 0.9 if store[:name] == "shell" min = price if price < min end end minend
- 38. Declarative Liquerdef expensive_boose_nearby (liquer_stores) nearby = ->(d, x) { x[:d] < d }.curry near = nearby.(5.0) myPrice = ->(x) { x[:name] == "shell" ? x[:price]*0.9 : x[:price] } liquer_stores. find_all(&near). recognize collect(&myPrice). SQL ? maxend
- 39. Generators / Sequence / Inﬁnite ...# Functions that return a sequence of values# Here: fibonacci as infinite yielderfibonacci = Enumerator.new do |list| a = b = 1 loop { list.yield a; a,b = b,a+b }endfibonacci.take(10) # [1, .. , 55]fibonacci.take(15) # [1, .. , 377, 610]
- 40. Enumerable as Classclass Fibs include Enumerable def each a = b = 1; loop { yield a; a,b = b,a+b }; endendFibs.new.take(10)
- 41. Merci

No public clipboards found for this slide

×
### Save the most important slides with Clipping

Clipping is a handy way to collect and organize the most important slides from a presentation. You can keep your great finds in clipboards organized around topics.

Be the first to comment