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

Functional Programming For Rubyists

Lucas Dohmen
February 20, 2013

Functional Programming For Rubyists

What is functional programming? And what can a Rubyists do with this knowledge? I gave this talk at the wonderful Cologne.rb :)

PS: There is a little mistake on the slides ;) I noticed it during the presentation – but now it's a nice exercise for you :P

PPS: "Why doesn't it succeed" is just a theory I believe in and in no way "fact" – just to make that clear ;)

Lucas Dohmen

February 20, 2013
Tweet

More Decks by Lucas Dohmen

Other Decks in Programming

Transcript

  1. RWTH Aachen, Computer Science Student triAGENS GmbH, Developer moon lum

    moonbeamlabs by Lucas Dohmen Functional Pro rammin for Rubyists λ
  2. “ Ruby is like Smalltalk and LISP ot to ether

    and ot a love child and then went o to work and hired Perl to be the nanny. Josh Susser in Thinkin in Objects (RubyConf 2012)
  3. Models of Computation Turin M achine Church‘s λ-Calculus First order

    lo ic Functional Pro ram m in Lo ical Pro rammin Im perative Lan ua es
  4. Church-Turin thesis • All al orithmically computable functions can be

    pro rammed on a Turin Machine (Turin ) • All al orithmically computable functions can be pro rammed with the λ-calculus (Church) • Corollary: Turin Machines and λ-calculus can do all the same stu (Dohmen)
  5. Functional Lan ua es • Lisp Family • Scheme, Common

    Lisp, Clojure (& Dylan) • ML Family • Haskell • Erlan • Scala
  6. LISP vs. Haskell • Invented by McCarthy (1958) • Used

    since the dawn of time • You can use it in any paradi m (see CLOS) • Uncountable number of dialects • Desi n by committee (First draft 1990) • Developed in the Ivory Tower • Purity and Laziness as hi hest principles • One clearly defined lan ua e
  7. LISP vs. Haskell • Invented by McCarthy (1958) • Used

    since the dawn of time • You can use it in any paradi m (see CLOS) • Uncountable number of dialects • Desi n by committee (First draft 1990) • Developed in the Ivory Tower • Purity and Laziness as hi hest principles • One clearly defined lan ua e C was introduced in 1972
  8. A short example (( x. plus x 1) 4) With

    iven δ: = {plus( x, y ) ! x + y } (plus 4 1) β-reduction
  9. A short example (( x. plus x 1) 4) With

    iven δ: = {plus( x, y ) ! x + y } (plus 4 1) β-reduction δ-reduction 4
  10. Quiz Time (yep, the theory stu is over) a =

    puts "b" Where is the side e ect?
  11. • One of the hard parts of testin • Haskell

    only allows side e ects with Monads • Ruby or LISP do not mark them in any way • In Haskell unit testin is really simple Side E ects
  12. No Proper Tail Calls • The bi di erence between

    iterative and recursive pro rammin • Without tail call optimization, every recursive call will add another frame to the call stack • Rule of Thumb: If your lan ua e doesn‘t have PTCs, you should hold your horses with recursive functions
  13. • In Ruby they all take blocks, not methods (doesn‘t

    make them less hi her order) • You all know each • …but there are also map, reduce, inject… • Look into the documentation of Enumerable :) Hi her Order Functions
  14. How is it implemented? def collect if block_given? ary =

    [] each do |*o| ary << yield(*o) end ary else to_enum :collect end end alias_method :map, :collect (Implementation in Rubinius)
  15. How is it implemented? (Implementation in Rubinius) def each return

    to_enum(:each) unless block_given? i = @start total = i + @total tuple = @tuple while i < total yield tuple.at(i) i += 1 end self end
  16. Lazy Evaluation • Only evaluate a statement if there is

    no way around that • Ruby is quite lazy • But Haskell is really, really lazy • I‘m talkin Dude-level lazy 1 or this_variable_does_not_exist # => 1
  17. Show me somethin • Task: Find the sum of the

    first x numbers that are dividable by 3 or 5 • First lets write it in idiomatic Haskell • Then lets emulate it with Ruby (2.0)
  18. -- Step 1: -- An infinite list of all positive

    integers [1..] -- Step 2: -- Now only those that are dividable by 3 and 5 [n | n <- [1..], n `mod` 3 == 0 || n `mod` 5 == 0]
  19. -- Step 1: -- An infinite list of all positive

    integers [1..] -- Step 2: -- Now only those that are dividable by 3 and 5 [n | n <- [1..], n `mod` 3 == 0 || n `mod` 5 == 0] This is a so called uard [ n | n 2 N, n mod 3 = 0 , n mod 5 = 0] It is inspired by… math!
  20. -- Step 1: -- An infinite list of all positive

    integers [1..] -- Step 2: -- Now only those that are dividable by 3 and 5 [n | n <- [1..], n `mod` 3 == 0 || n `mod` 5 == 0] -- Step 3: -- Only the first x take x [...]
  21. -- Step 1: -- An infinite list of all positive

    integers [1..] -- Step 2: -- Now only those that are dividable by 3 and 5 [n | n <- [1..], n `mod` 3 == 0 || n `mod` 5 == 0] -- Step 3: -- Only the first x take x [...] -- Step 4 -- Add them foldl (+) 0 (take x [...])
  22. foldl (+) 0 (take x [n | n <- [1..],

    n `mod` 5 == 0 || n `mod` 3 == 0])
  23. foldl (+) 0 (take x [n | n <- [1..],

    n `mod` 5 == 0 || n `mod` 3 == 0]) (1..Float::INFINITY)
  24. foldl (+) 0 (take x [n | n <- [1..],

    n `mod` 5 == 0 || n `mod` 3 == 0]) (1..Float::INFINITY).lazy
  25. . .select { |n| n % 3 == 0 ||

    n % 5 == 0 } foldl (+) 0 (take x [n | n <- [1..], n `mod` 5 == 0 || n `mod` 3 == 0]) (1..Float::INFINITY).lazy
  26. . .select { |n| n % 3 == 0 ||

    n % 5 == 0 } foldl (+) 0 (take x [n | n <- [1..], n `mod` 5 == 0 || n `mod` 3 == 0]) (1..Float::INFINITY).lazy .take(x)
  27. . .select { |n| n % 3 == 0 ||

    n % 5 == 0 } foldl (+) 0 (take x [n | n <- [1..], n `mod` 5 == 0 || n `mod` 3 == 0]) (1..Float::INFINITY).lazy .take(x).inject(0, :+)
  28. Fun Fact • Fold is also known as foldl, reduce,

    accumulate, compress or inject • This is of course not confusin at all • LISP is to blame
  29. Immutability • In Haskell, everythin is immutable • In Ruby,

    almost everythin is mutable • hamster em: E cient, Immutable, Thread- Safe Collection classes for Ruby • adamantium em: Immutable extensions to objects
  30. require "adamantium" class Wolverine include Adamantium attr_accessor :health def initialize

    @health = 100 end end wolverine = Wolverine.new p wolverine.health #=> 100 wolverine.health = 211 #=> can't modify frozen Wolverine (RuntimeError)
  31. require "adamantium" class Wolverine include Adamantium attr_accessor :health def initialize

    @health = 100 end end wolverine = Wolverine.new p wolverine.health #=> 100 wolverine.health = 211 #=> can't modify frozen Wolverine (RuntimeError) Warnin ! This lib is confusin
  32. Why doesn‘t it succeed? • Not a ood model for

    the world • Lar e systems tend to separate into communicatin sub systems… • … and that is pretty much Alan Kay‘s idea
  33. Still… • It‘s a lot of fun to play around

    with • It‘s a ood fit for certain problem types • It‘s a nice exercise for the brain to try a di erent paradi m • … and immutability and no side e ects are the key to parallel pro rammin ;)
  34. Further Readin /Listenin • Book: Land Of Lisp • Talk:

    Jim Weirich‘s Y Not – Adventures in Functional Pro rammin • Blo Article: Pro rammin with Nothin