6. Object + callable interface
class CallablePORO
def call
# TODO
end
def self.call
# TODO
end
end
CallablePORO.call
CallablePORO.new.call
7. Callable interface in action
Rack provides a minimal interface between webservers
that support Ruby and Ruby frameworks.
To use Rack, provide an object that responds to the call method.
13. Purity
Pure Functions are very simple functions.
They only operate on their input parameters.
Pure Functions will always produce the same output given the same inputs.
Most useful Pure Functions must take at least one parameter.
All useful Pure Functions must return something.
Pure functions have no side effects.
14. Purity
z = 10
def sum(x, y)
x + y
end
def just10
10
end
Pure functions
15. Purity
z = 10
def sum(x, y)
x + y + z
end
def convert(file_name)
input = File.read(file_name)
output = JSON2YML.convert(input)
File.write('output.yml', output)
end
Impure functions
16. Purity
You don’t just write Pure Functions.
Since programs have to interface to the real world,
some parts of every program must be impure.
The goal is to minimize the amount of impure code
and segregate it from the rest of our program.
18. Immutability
str = 'bite my shiny metal ass'
str.object_id # => 70317488591440
upper_str = str.upcase
upper_str # => "BITE MY SHINY METAL ASS"
upper_str.object_id # => 70317484572200
The simplest examples are the primitive objects:
Symbol, String, Integer, TrueClass(true), FalseClass(false), NilClass(nil) …
19. Immutability
Value Objects
• Small object that represents a simple entity whose equality is not based on identity
• Value objects have multiple attributes
• Attributes should be immutable throughout its life cycle
• Equality is determined by its attributes (and its type)
20. Immutability
There are no variables in Functional Programming.
Stored values are still called variables because of history but they are
constants, i.e. once x takes on a value, it’s that value for life.
x = 5
x = x + 1
In math, x can never be equal to x + 1
22. Higher-Order Functions
In Functional Programming, a function is a first-class citizen of the language.
In other words, a function is just another value.
Since functions are just values, we can pass them as parameters.
Higher-order Functions either take functions as parameters, return functions or both.
23. Higher-Order Functions
# returns value
values = [1, 2, 3, 4, 5]
values.map do |value|
value * value
end # => [1, 4, 9, 16, 25]
# returns function
def adder(a, b)
lambda { a + b }
end
adder_fn = adder(1, 2) # => #<Proc: (lambda)>
adder_fn.call # => 3
25. Closures
Techniques for implementing lexically scoped name binding
in languages with first-class functions
When a function is created, all of the variables in its scope at the time of
creation are accessible to it for the lifetime of the function.
A function exists as long as there still a reference to it.
A closure is a function’s scope that’s kept alive by a reference to that function.
26. Closures
outer = 1
def m
inner = 99
yield inner
puts "inner var = #{inner}"
end
m { |inner| outer += inner } # => 99
puts "outer var = #{outer}" # => 100
28. Functional Composition
Code reuse sounds great but is difficult to achieve.
Make the code too specific and you can’t reuse it.
Make it too general and it can be too difficult to use in the first place.
So what we need is a balance between the two, a way to make smaller,
reusable pieces that we can use as building blocks
to construct more complex functionality.
29. Functional Composition
a = lambda { |x| x + 4 }
b = lambda { |y| y / 2 }
a.compose(b).call(4) #=> 6
b.compose(a).call(4) #=> 4
30. Functional Composition
add10 = -> value { value + 10 }
mult5 = -> value { value * 5 }
compose = -> (fn1, fn2) {
-> value { fn1.(fn2.(value)) }
}
add10mult5 = compose.(mult5, add10)
mult5add10 = compose.(add10, mult5)
add10mult5.(5) # => 75
mult5add10.(5) # => 35
31. Functional Composition
In math, f ∘ g is functional composition and is read “f composed with g” or,
more commonly, “f after g”. So (f ∘ g)(x) is equivalent to calling f after
calling g with x or simply, f(g(x)).
33. Point-Free Notation
A style of writing functions without having to specify the parameters.
First, we don’t have to specify redundant parameters. And since we don’t have to
specify them, we don’t have to think up names for all of them.
Second, it’s easier to read and reason about since it’s less verbose. This example is
simple, but imagine a function that took more parameters.
Tacit programming is a programming paradigm in which a function definition
does not include information regarding its arguments, using combinators and
function composition instead of variables
39. Common Functional
Functions
This function is usually called fold in Functional Languages.
Higher-Order Functions for processing data structures
for building up new values.
Map, Reduce, Select, Find …
Functional Programming uses recursion to do looping.
44. Not off all FP concepts
are applicable in Ruby
не все концепции из ФП
применимы к ООП
Правильнее будет сказать так, фп
языки построены на данных
концепциях, в этом их особенность,
В ОО языках мы можем лишь
имитировать данные концепции
55. Callable Object
class LaunchShuttle
attr_reader :shuttle
def initialize(shuttle)
@shuttle = shuttle
end
def call
CheckFuelSystem.new(shuttle).call
ConfirmLaunchReady.new(shuttle).call
end
end
56. Callable Object
class LaunchShuttle
attr_reader :shuttle
def initialize(shuttle)
@shuttle = shuttle
end
def call
CheckFuelSystem.new(shuttle).call
ConfirmLaunchReady.new(shuttle).call
end
end
76. Inspired by
• Functional Architecture for the Practical Rubyist -
RedDotRubyConf 2017: https://www.youtube.com/watch?
time_continue=962&v=7qnsRejCyEQ
• Next Generation Ruby Web Appswith dry-rb, ROM, and Roda -
RedDotRubyConf 2016: https://www.youtube.com/watch?
v=6ecNAjVWqaI
• Full Stack Fest 2015: Blending Functional and OO Programming
in Ruby, by Piotr Solnica: https://www.youtube.com/watch?
v=rMxurF4oqsc
• RubyConf 2017: 4 Programming Paradigms in 45 Minutes by Aja
Hammerly: https://www.youtube.com/watch?v=3TBq__oKUzk