RWTH Aachen, Computer Science Student
triAGENS GmbH, Developer
moon lum moonbeamlabs
by Lucas Dohmen
Functional Pro rammin for Rubyists
λ
Slide 2
Slide 2 text
Ruby
Smalltalk
Perl
Lisp
(Matz)
Slide 3
Slide 3 text
“
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)
Slide 4
Slide 4 text
Imperative Declarative
Procedural OOP Lo ical Functional
Slide 5
Slide 5 text
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
Slide 6
Slide 6 text
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)
Slide 7
Slide 7 text
Functional Lan ua es
• Lisp Family
• Scheme, Common Lisp, Clojure (& Dylan)
• ML Family
• Haskell
• Erlan
• Scala
Slide 8
Slide 8 text
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
Slide 9
Slide 9 text
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
Slide 10
Slide 10 text
λ-Calculus
LISP is a pimped Lambda Calculus
The smallest pro rammin lan ua e that exists
Slide 11
Slide 11 text
A short example
((
x.
plus
x
1) 4)
Slide 12
Slide 12 text
A short example
((
x.
plus
x
1) 4)
(plus 4 1)
β-reduction
Slide 13
Slide 13 text
A short example
((
x.
plus
x
1) 4)
With iven δ:
= {plus(
x, y
) !
x
+
y
}
(plus 4 1)
β-reduction
Slide 14
Slide 14 text
A short example
((
x.
plus
x
1) 4)
With iven δ:
= {plus(
x, y
) !
x
+
y
}
(plus 4 1)
β-reduction
δ-reduction
4
Slide 15
Slide 15 text
Why you can‘t use Ruby
as a functional lan ua e
Slide 16
Slide 16 text
Quiz Time
(yep, the theory stu is over)
a = puts "b"
Where is the side e ect?
Slide 17
Slide 17 text
• 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
Slide 18
Slide 18 text
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
Slide 19
Slide 19 text
Where you can use
Ruby‘s functional
herita e
Slide 20
Slide 20 text
• 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
Slide 21
Slide 21 text
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)
Slide 22
Slide 22 text
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
Slide 23
Slide 23 text
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
Slide 24
Slide 24 text
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)
Slide 25
Slide 25 text
No content
Slide 26
Slide 26 text
-- Step 1:
-- An infinite list of all positive integers
[1..]
Slide 27
Slide 27 text
-- 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]
Slide 28
Slide 28 text
-- 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!
Slide 29
Slide 29 text
-- 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 [...]
Slide 30
Slide 30 text
-- 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 [...])
Slide 31
Slide 31 text
foldl (+) 0 (take x [n | n <- [1..], n `mod` 5 == 0 || n `mod` 3 == 0])
Slide 32
Slide 32 text
foldl (+) 0 (take x [n | n <- [1..], n `mod` 5 == 0 || n `mod` 3 == 0])
(1..Float::INFINITY)
Slide 33
Slide 33 text
foldl (+) 0 (take x [n | n <- [1..], n `mod` 5 == 0 || n `mod` 3 == 0])
(1..Float::INFINITY).lazy
Slide 34
Slide 34 text
. .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
Slide 35
Slide 35 text
. .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)
Slide 36
Slide 36 text
. .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, :+)
Slide 37
Slide 37 text
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
Slide 38
Slide 38 text
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
Slide 39
Slide 39 text
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)
Slide 40
Slide 40 text
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
Slide 41
Slide 41 text
Wrappin up…
Slide 42
Slide 42 text
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
Slide 43
Slide 43 text
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 ;)
Slide 44
Slide 44 text
Further
Readin /Listenin
• Book: Land Of Lisp
• Talk: Jim Weirich‘s Y Not – Adventures in
Functional Pro rammin
• Blo Article: Pro rammin with Nothin