Thinking Functionally In Ruby

Loading...

Flash Player 9 (or above) is needed to view presentations.
We have detected that you do not have it on your computer. To install it, go here.

0 comments

Post a comment

    Post a comment
    Embed Video
    Edit your comment Cancel

    1 Favorite

    Thinking Functionally In Ruby - Presentation Transcript

    1. THINKING FUNCTIONALLY IN RUBY. @tomstuart
    2. 1: Functional programming is a pretty neat idea.
    3. 2: Enumerable contains some useful methods.
    4. I hope these things are connected.
    5. 1. (Functional programming is a pretty neat idea)
    6. What is functional programming?
    7. A programming style.
    8. Two broad families of languages:
    9. • Scheme • Common Lisp • Dylan • Clojure 1. Lisp-like • Dynamically typed • Homoiconic (code is data) • Lists are fundamental
    10. • Standard ML • Haskell • OCaml • Scala (sort of) 2. ML-like • Statically typed (+ reconstruction) • Code is not data • ADTs and pattern matching
    11. Functions as values
    12. What is a function?
    13. 1 2 7 6 2 3 3 6 1 7 5 4 8 4
    14. Functions as values
    15. “First-class functions” “closures”, “lambdas”, “anonymous functions” Implies: higher-order functions
    16. No side effects
    17. Values are immutable All functions do is return their result No state No I/O
    18. (In reality, different languages accomplish this to varying degrees.)
    19. Implies: recursion Implies: persistent data structues
    20. So what?
    21. Unfortunately...
    22. Declarative T! W HA programming is counterintuitive when youʼre accustomed to imperative HOW ! programming
    23. Copying is expensive
    24. But!
    25. Referential transparency “an expression can be replaced with its value” • Good for efficiency • caching/memoisation/inlining • ultimately more efficient • Good for programmer understanding • state is incredibly hard to deal with • ultimately more intuitive • Good for code reuse and testing
    26. Highly expressive Strongly compositional Deeply satisfying
    27. Future-proof • Mooreʼs Law is running out of steam • similar transistor density, more cores • The futureʼs concurrent • Concurrent access to mutable state is hard... • but not if you donʼt have mutable state! • Parallelising an algorithm is hard... • but itʼs easier if your code isnʼt overspecified
    28. OK seriously: so what?
    29. Ruby can do some of this. Not really a functional language, but we can pretend and get some of the benefits.
    30. Use function values blocks, procs lambda { |x| x + 1 }
    31. Consider treating your values as immutable State is rarely worth it. It will kill you in the end.
    32. http://clojure.org/state
    33. Use the functional-flavoured parts of the standard library
    34. Think functionally. Be declarative. What, not how.
    35. 2. (Enumerable contains some useful methods)
    36. Enumerable#zip
    37. [1, 2, 3, 4]. zip([5, 6, 7, 8])
    38. 1 2 3 4 5 6 7 8
    39. 1 5 2 6 3 7 4 8
    40. [ ] [1 , 5],[2 , 6],[3 , 7],[4 , 8]
    41. [1, 2, 3, 4]. zip([5, 6, 7, 8], [9, 10, 11, 12])
    42. Enumerable#select (a.k.a. #find_all)
    43. { |x| x.odd? }
    44. 1 ?
    45. 1 ! ? 1
    46. 1 2 ! ? 1 ?
    47. 1 2 ! ? 1 " ? 2
    48. [1, 2, 3, 4]. select { |x| x.odd? }
    49. 1 2 3 4 ? ? ? ?
    50. 1 2 3 4 ! ? 1 " ? 2 ! ? 3 " ? 4
    51. 1 3 ! ? 1 ! ? 3 1 3
    52. [ 1, 3 ]
    53. Enumerable#partition
    54. [1, 2, 3, 4]. partition { |x| x.odd? }
    55. 1 2 3 4 ? ? ? ?
    56. 1 2 3 4 ! ? 1 " ? 2 ! ? 3 " ? 4
    57. 1 3 2 4 ! ? ! ? " ? " ?
    58. 1 3 2 4 ! ? ! ? " ? " ? 1 3 2 4
    59. [[ 1 , 3 ] , [ 2 , 4 ]]
    60. Enumerable#map (a.k.a. #collect)
    61. { |x| x * 3 }
    62. 2 ×3 6
    63. 2 ×3 2 6
    64. [1, 2, 3, 4]. map { |x| x * 3 }
    65. 1 2 3 4 ×3 3 ×3 6 ×3 9 ×3 12
    66. 1 2 3 4 ×3 1 ×3 2 ×3 3 ×3 4 3 6 9 12
    67. [ , , , ] 3 6 9 12
    68. Enumerable#inject (a.k.a. #reduce)
    69. { |x, y| x + y }
    70. 3 5 8 +
    71. 3 5 3+5 8
    72. [1, 2, 3, 4]. inject(0) { |x,y| x+y }
    73. 0 1 1 + 2 3 + 3 6 + 4 + 10
    74. 0 1 0+1 1 2 1+2 3 3 3+3 6 4 6 + 4 10
    75. module Enumerable def inject(initial) result = initial for element in self result = yield(result, element) end result end end
    76. a.k.a. “left fold” (foldl, fold_left)
    77. 0 1 2 3 4
    78. 10 (((0 + 1) + 2) + 3) + 4
    79. ...versus “right fold” (foldr, fold_right)
    80. 1 2 3 4 0
    81. 10 1 + (2 + (3 + (4 + 0)))
    82. The initial argument is optional...
    83. [1, 2, 3, 4]. inject { |x,y| x+y }
    84. [2, 3, 4].4]. [1, 2, 3, inject(1)|x,y| x+yx+y } inject { { |x,y| }
    85. ...but only if the output is the same type as the input...
    86. >> ['El', 'rug']. inject(0) { |l,s| l + s.length } => 5 >> ['El', 'rug']. inject { |l,s| l + s.length } TypeError: can't convert Fixnum into String from (irb):1:in `+' from (irb):1 from (irb):1:in `inject' from (irb):1:in `each' from (irb):1:in `inject' from (irb):1
    87. ...and itʼs meaningful to get nil when the collection is empty
    88. >> [].inject { |x,y| x+y } => nil >> [].inject(0) { |x,y| x+y } => 0 >> [].inject(1) { |x,y| x*y } => 1
    89. P O SE ! C O M
    90. [1, 2, 3, 4]. map { |x| x * 3 }. inject(0) { |x| x+y }
    91. 1 2 3 4 ×3 3 ×3 6 ×3 9 ×3 12 0 3 + 9 + + 18 + 30
    92. 1 2 3 4 ×3 1 ×3 2 ×3 3 ×3 4 0 3 0+3 3 6 3+6 9 9 9 + 9 18 12 18+12 30
    93. I am so excited. What now?
    94. Review your Ruby code. Func it up.
    95. result = '' for name in names unless result.empty? result << ', ' end result << name end result
    96. ! result = '' for name in names unless result.empty? result << ', ' end result << name end result names.join(', ')
    97. def count_mines_near(x, y) count = 0 for i in x-1..x+1 for j in y-1..y+1 count += 1 if mine_at?(i, j) end end count end
    98. ! def count_mines_near(x, y) count = 0 for i in x-1..x+1 for j in y-1..y+1 count += 1 if mine_at?(i, j) end end count end def count_mines_near(x, y) ((x-1..x+1).entries * 3).sort. zip((y-1..y+1).entries * 3). select { |x, y| mine_at?(x, y) }. length end
    99. [1, 2, 3, 1, 2, 3, 1, 2, 3].sort = [1, 1, 1, 2, 2, 2, 3, 3, 3] def count_mines_near(x, y) # = (2, 8) ((x-1..x+1).entries * 3).sort. zip((y-1..y+1).entries * 3). select { |x, y| mine_at?(x, y) }. length end
    100. [1, 2, 3, 1, 2, 3, 1, 2, 3].sort = [1, 1, 1, 2, 2, 2, 3, 3, 3].zip( [7, 8, 9, 7, 8, 9, 7, 8, 9]) = [[1, 7], [1, 8], [1, 9], [2, 7], [2, 8], [2, 9], [3, 7], [3, 8], [3, 9]] def count_mines_near(x, y) # = (2, 8) ((x-1..x+1).entries * 3).sort. zip((y-1..y+1).entries * 3). select { |x, y| mine_at?(x, y) }. length end
    101. [1, 2, 3, 1, 2, 3, 1, 2, 3].sort = [1, 1, 1, 2, 2, 2, 3, 3, 3].zip( [7, 8, 9, 7, 8, 9, 7, 8, 9]) = [[1, 7], [1, 8], [1, 9], [2, 7], [2, 8], [2, 9], [3, 7], [3, 8], [3, 9]].select {…} = [[1, 8], [3, 7]].length = 2 def count_mines_near(x, y) # = (2, 8) ((x-1..x+1).entries * 3).sort. zip((y-1..y+1).entries * 3). select { |x, y| mine_at?(x, y) }. length end
    102. [ [1, 7], [1, 8], …, [1, 1007], [2, 7], [2, 8], …, [2, 1007], …, …, …, [1000, 7], [1000, 8], …, [1000, 1007], [1001, 7], [1000, 8], …, [1001, 1007]] def count_mines_near(x, y) ((x-500..x+500).entries * 1001).sort. zip((y-500..y+500).entries * 1001). select { |x, y| mine_at?(x, y) }. length end
    103. [ [1, 7], [1, 8], …, [1, 1007], [2, 7], [2, 8], …, [2, 1007], …, …, …, [1000, 7], [1000, 8], …, [1000, 1007], [1001, 7], [1000, 8], …, [1001, 1007]] 173 96 121 78 237 705
    104. def numbers_near(n, radius) ((n - radius)..(n + radius)).entries end def squares_near(x, y, radius) diameter = (radius * 2) + 1 (numbers_near(x, radius) * diameter). sort. zip(numbers_near(y, radius) * diameter) end def count_mines_near(x, y, radius = 1) squares_near(x, y, radius). select { |x, y| mine_at?(x, y) }. length end
    105. Learn a functional language • OCaml • Scheme (Google “SICP”) • Clojure • Scala • Haskell? Erlang?
    106. Thanks! @tomstuart / tom@experthuman.com
    107. http://www.flickr.com/photos/somemixedstuff/2403249501/ http://en.wikipedia.org/wiki/File:Modified-pc-case.png

    + RossC0RossC0, 1 month ago

    custom

    199 views, 1 favs, 4 embeds more stats

    More info about this document

    © All Rights Reserved

    Go to text version

    • Total Views 199
      • 176 on SlideShare
      • 23 from embeds
    • Comments 0
    • Favorites 1
    • Downloads 9
    Most viewed embeds
    • 10 views on http://www.soup.io
    • 5 views on http://h3x.soup.io
    • 5 views on http://agileweb.org
    • 3 views on http://www.agileweb.org

    more

    All embeds
    • 10 views on http://www.soup.io
    • 5 views on http://h3x.soup.io
    • 5 views on http://agileweb.org
    • 3 views on http://www.agileweb.org

    less

    Flagged as inappropriate Flag as inappropriate
    Flag as inappropriate

    Select your reason for flagging this presentation as inappropriate. If needed, use the feedback form to let us know more details.

    Cancel
    File a copyright complaint
    Having problems? Go to our helpdesk?

    Categories