Functional Geekery
for an Imperative Mind
Rajeev N B
Application Developer
RubyConf India 2015
Rich Hickey
Words of Wisdom
Functional Programming is unfamiliar territory for most,
If you want everything to be familiar you will never learn anything new
- Rich Hickey (Author of Clojure and Datomic)
Simon Peyton Jones
Nirvana
Functional Programming?
"Functional Programming is so called because a program consists entirely of functions"
- John Hughes , Why Functional Programming Matters
Concepts
Function Composition
(f o g)
It is act of pipelining the result of one function to the input of another, creating an entirely new function.
Function Composition
- Combine simple functions to build more complicated ones.
- Glueing Functions Together.
- Functional languages provide constructs in the language.
- Encourages factoring.
- Encourages code reuse, readability and maintainability.
- Modularise the code.
# => g(x) = x * 1
g = -> (x) { x + 1 }
# => f(x) = x * x
f = -> (x) { x * x }
# Function composition => g(f(x)
fg = -> (x) { f[g[x]] }
# call
fg[3]
# => 16
Ruby
Haskell
-- g(x) = x + 1
g :: (Num a) => a -> a
g x = x + 1
-- f(x) = x * x
f :: (Num a) => a -> a
f x = x * x
-- Composite function g(f(x)
gf = f . g
Lazy Evaluation
Expressions are not evaluated when they are bound to variables,
but their evaluation is deferred until their results are needed by other computations.
- Haskell Wiki
Lazy Evaluation
- Call By Need (Sharing).
- Supports Infinite data structures.
- Increases Performance.
- Uses Thunks.
# Strict Evaluation
[1, 2, 3/0, 4].length
# => ZeroDivisionError: divided by 0
# Simulate Lazy Evaluation with Lambdas
[1, 2, -> { 3/0 }, 4].length
# => 4
Strict vs Lazy
Ruby ( Infinite Lists )
# Infinite range ( Generator )
range = 1..Float::INFINITY
# Non Lazy will run forever
range.collect { |val| val * val }.take(10).to_a
# Lazy
range.lazy.collect { |val| val * val }.take(10).to_a
# => [1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
Haskell ( Infinite Lists )
-- Infinite generator
range = [1..]
-- Square function
square :: ( Num a ) => a -> a
square x = x * x
result = take 10 (map square range)
-- => [1,4,9,16,25,36,49,64,81,100]
Words of Wisdom
"The Language that does not affect the way you think about programming, is not worth knowing."
- Alan Perlis
Higher Order Functions
Functions which either take functions as parameters or return functions as return values.
Ruby
def double(x)
x * x
end
# map higher order function
#
Array(1..10).map { |a| double(a) }
# => [1, 4, 9, 16, 25, 36, 49, 64, 81, 100]
# Function returning function
#
def functionReturn
-> (x) { x * x }
end
Haskell
double :: ( Num a ) => a -> a
double x = x * 2
-- map takes double as argument
-- function taking function as argument
higher_order_function = map double [1..10]
-- => [2,4,6,8,10,12,14,16,18,20]
-- Function returning function as return value
functionReturn :: ( Num a ) => (a -> a)
functionReturn = \x -> x * x
Currying
Translating the evaluation of a function that takes multiple arguments into evaluating a sequence of functions, each with a single argument (partial application).
# Currying one argument at a time
# Partial application of arguments
add = proc { |x, y, z| x + y + z }
add5 = add.curry.call(5)
# equal to add.curry.call(5).call(6)
add5and6 = add5.call(6)
add5and6.call(10) # => 21
Ruby
Haskell
-- In Haskell functions always take a single argument
-- Partial application of arguments
-- Currying
add :: Int -> Int -> Int
add x y = x + y
Pure Functions
returns exactly the same result every time it's called with the same set of arguments
No Side Effects
Referential Transparency
- Property of Pure Functional Languages.
- No side effects.
- Easier to reason about programs.
Recursion
Solution to a problem depends on solutions to smaller instances of the same problem
- Wikipedia
Iteration in Functional Languages is done through Recursion.
Ruby
# Recursion in Ruby
def summify(list)
return 0 if list.empty?
element, *rest = list
element + summify(rest)
end
Haskell
summify :: ( Num a ) => [a] -> a
-- summify calling itself
summify [] = 0
summify [x] = x
summify (x:xs) = x + summify xs
Immutability
Unchanging over time or unable to be changed.
Immutable object is an object whose state cannot be modified after it is created
Immutable Data Structures
- Supports in Concurrency and Security.
- Performance Impact ?
- Shares structure.
Imperative
vs
Functional
total = 0
i = 0
while i <= 10
total += i
i = i + 1
end
total
total = (1..10).inject(:+)
Imperative
Functional
Imperative vs Functional
Words of Wisdom
"Imperative programming is like giving instructions to an idiot."
"Functional programming is like describing your problem to a mathematician"
Why Functional Programming Matters ?
- Modularity of code.
- Lock Free Concurrency.
- Concise and more expressive.
References
Thanks
Functional Geekery
By Rajeev Bharshetty
Functional Geekery
- 1,735