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,593