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

Ruby Vs. The Titans Of FP

Ruby Vs. The Titans Of FP

Clojure, Haskell and Javascript reign as the dominant functional languages of our era. But surely anything they can do, Ruby can do better? And what is it that they actually do? Come learn about three core concepts of functional programming, and see how Ruby stacks up against its peers when it comes to making them powerful.

B9cbf74b1368eca05f77da23faf7848a?s=128

Cassandra Cruz

November 12, 2016
Tweet

Other Decks in Programming

Transcript

  1. Ruby Vs. The Titans of FP Cassandra Cruz (@celkamada)

  2. Bit about me • Hobbyist programmer for a decade +

    • Fascinated with Functional Programming • Relatively new to industry (currently 8 months at Mavenlink) • Working at Mavenlink is my first real experience with Ruby Hi!
  3. Vs.

  4. What is Functional Programming?

  5. Functional Programming (to me) A programming paradigm that focuses on

    functions as transformations on generic data, as opposed to the modeling of objects.
  6. Ex: OO vs. FP Login Object • Knows the state

    of a session • Knows how to validate itself Login Object • Knows the state of a session Login Library • Knows how to validate the login object
  7. Why is that a good thing? • Easier to reuse

    logic • Can compose smaller units of logic together • Can result in cleaner, more performant code
  8. What are the key features of a FP Language? •

    Higher-order functions • Currying • Composition • Functional Purity • Immutability
  9. What are we going to look at today? • Higher-order

    functions (vs Clojure) • Currying (vs Haskell) • Composition (vs Javascript) • Functional Purity • Immutability
  10. Clojure

  11. What it Clojure? Born: 2007 Family: Lisp What makes it

    a functional language: • Higher-order functions • First-class functions • Immutable Data Structures
  12. Example of a function call in Clojure (function argument1 argument2

    argument3)
  13. What a program ends up looking like (defn take [n

    coll] (lazy-seq (when (pos? n) (when-let [s (seq coll)] (cons (first s) (take (dec n) (rest s) ))))))
  14. Map In Clojure (map function collection)

  15. Map In Clojure (map function collection) Function Arguments

  16. Map In Clojure (map function collection) Transform function Ex: increment

    The list of items we’re transforming Ex: [1,2,3]
  17. Map increment over 1-5 (map inc [1 2 3 4

    5]) ;; returns (2 3 4 5 6)
  18. What is a Higher-Order Function? A higher order function is

    a function that takes in functions as arguments or returns another function (map function collection) function that takes a function
  19. Can we use this in Ruby? YES!

  20. Map in Ruby map = proc { }

  21. Map in Ruby map = proc { |function, collection| }

  22. Map in Ruby map = proc { |function, collection| collection.map(&function)

    }
  23. Map in Ruby map = proc { |f, coll| coll.map(&f)

    }
  24. How do we use this? inc = proc { |x|

    x + 1 } # proc that adds 1 to input nums = [2,3,4] # data for us to map over map.call(inc, nums) # returns [3,4,5] map.(inc, nums) # syntactic sugar to hide the `call`
  25. A more complex example invalidateLogin = proc { |login| login.deleted_at

    = Time.now } logins = [login1, login2, login3] map.(invalidateLogins, logins)
  26. Haskell

  27. What is Haskell? Born: 1990 Family: ML What makes it

    a functional language: • Curried Functions • Pure Functions • Type Inference
  28. What does a function call look like in Haskell? inc

    = (+) 1 -- our new inc function map inc [2,3,4] -- returns [3,4,5]
  29. Wait, what was with that inc?

  30. Hindley-Milner Type System • Can express the signatures of a

    function • Can be used in Haskell to annotate types to be checked
  31. An Example: Add (As we’re used to it) Add ::

    (a, a) -> a Function Name Arguments Function Result
  32. An Example: Add (As Haskell does it) (+) :: a

    -> a -> a Function Name Arguments Function Result
  33. What Happened in our inc function inc = (+) 1

  34. What actually happened to inc (+) :: a -> a

    -> a Pass in 1 here
  35. What actually happened to inc inc :: a -> a

  36. Curried Function A function that upon being applied to less

    than its total set of arguments returns another function that waits for the rest of its arguments.
  37. How to implement in Ruby add = proc { |x|

    # bind `x` using a closure }
  38. How to implement in Ruby add = proc { |x|

    proc { |y| # returns a proc that will receive `y` } }
  39. How to implement in Ruby add = proc { |x|

    proc { |y| x + y # internal proc returns x + y } }
  40. How to implement in Ruby add = proc { |x|

    proc { |y| x + y } } inc = add.(1) # binds x to 1
  41. How to implement in Ruby add = proc { |x|

    proc { |y| x + y } } inc = add.(1) inc.(2) # binds y to 2, returns 3
  42. How to implement in Ruby add = proc { |x|

    proc { |y| x + y } } inc = add.(1) inc.(2) map.(inc, [1,2,3]) # returns [2,3,4]
  43. How to implement in Ruby(the easy way) add = proc

    { |x, y| x + y }.curry inc = add.(1) inc.(2) # returns 3 add.(2, 3) # returns 5 map.(inc, [2,3,4]) # returns [3,4,5] Native Currying!
  44. On the order of arguments inc = add.(1) inc_map =

    map.(inc) nums = [1,2,3,4,5] inc_map.(nums) #returns [2,3,4,5,6] dec = add.(-1) dec_map = map.(dec) nums = [1,2,3,4,5] dec_map.(nums) #returns [0,1,2,3,4] Currying lets us build entire families of functions
  45. Javascript

  46. What is Javascript? Born: 1995 Family: Javascript What makes it

    a functional language: • First-class Functions • Closures • Strong FP Libraries
  47. How well does JS support FP? Despite the prevalence of

    FP concepts in JS, the core API doesn't really cater well to programming in a functional way in some places.
  48. FP Unfriendliness Example: JS var arr = [1,2,3] arr.map((x) =>

    x + 1) // map is a method arr.pop // mutates ;-;
  49. ...wait, doesn’t Ruby do those same things?

  50. FP Unfriendliness Example: Ruby arr = [1,2,3] arr.map{ |x| x

    + 1 } // map is a method arr.pop // mutates ;-;
  51. How do JS programmers fix this? Functional Libraries • Underscore

    • Lodash • Ramda
  52. My favorite thing in Ramda? Compose

  53. Have you ever done this? def fn (x) var1 =

    fn2(x) var2 = fn3(var1) var3 = fn4(var2) # 30 lines later... fn34(var33) end
  54. Compose to the rescue! import R from 'ramda' var add2

    = R.compose( R.add(1), R.add(1) ) add2(2) // returns 4
  55. A MapReduce function import R from 'ramda' // incAdd ::

    [a] -> b // R.reduce :: ((a, b) -> a) -> a -> [b] -> a // R.map :: (a -> b) -> [a] -> [b] var incAdd = R.compose( R.reduce(R.add, 0), R.map(R.inc) ) incAdd([1,2,3,4,5]) // returns 20
  56. Benefits of Compose

  57. Can Reuse Logic Easily const inc = add(1) const dec

    = add(-1) const c1 = compose(inc, dec) const c2 = compose(dec, inc)
  58. Can Compose Compositions const inc = add(1) const dec =

    add(-1) const c1 = compose(inc, dec) const c2 = compose(c1, inc)
  59. How do we do this in Ruby? compose = proc

    { |x, y| # two functions to compose }
  60. How do we do this in Ruby? compose = proc

    { |x, y| Proc{ |*args| # returns proc that takes in args } }
  61. How do we do this in Ruby? compose = proc

    { |x, y| Proc{ |*args| x.(y.(*args)) # invoke functions with the args } }
  62. How do we do this in Ruby? compose = proc

    { |x, y| Proc{ |*args| x.(y.(*args)) } } inc = add.(1) # create our friendly inc function
  63. How do we do this in Ruby? compose = proc

    { |x, y| Proc{ |*args| x.(y.(*args)) } } inc = add.(1) add2 = compose.(inc, inc) # compose `inc` with itself
  64. How do we do this in Ruby? compose = proc

    { |x, y| Proc{ |*args| x.(y.(*args)) } } inc = add.(1) add2 = compose.(inc, inc) add2.(4) # returns 6
  65. What if we want more than two functions? v_compose =

    proc { |*funcs| funcs.reduce(&compose) } add3 = v_compose.(inc, inc, inc) add3.(4) # returns 7
  66. What if we just want a gem? require ‘reductio’ inc

    = Reductio::Add.(1) add3 = Reductio::Compose.(inc, inc, inc) add3.(4) # returns 7
  67. What have we established Ruby can do? • Higher Order

    Functions • Composition • Currying
  68. The tools we have are enough!

  69. Vs.

  70. None
  71. Cassandra Cruz Github: lambdatastic Twitter: Celkamada Email: celkamada@gmail.com mavenlink.com/engineering Next

    Steps: • Dr. Frisby’s Mostly Adequate Guide to Functional Programming • github.com/lambdatastic/Reductio.rb • Tweet with #functionalruby for discussion • Tweet questions at me • Help with Reductio? Please? discord.me/transcord