functional programming with ruby - can make you look smart

Post on 26-May-2015

316 Views

Category:

Technology

0 Downloads

Preview:

Click to see full reader

DESCRIPTION

Functional programming can make you look smart and others feel stupid. Learn how with Ruby code can be found here: https://github.com/chenfisher/functional-programming-with-ruby Youtube: https://www.youtube.com/watch?v=Qzoh8w4OPtU

TRANSCRIPT

Functional ProgrammingMakes you look smart

“If you ask 100 programmers for their definition, you’ll likely receive 100 different answers”

- “The Joy of Clojure: Thinking the Clojure Way.”

Functional programming?

FP - proposed definition

Functional programming makes you look smart and others feel stupid

-- Matz

“Some may say Ruby is a bad rip-off of Lisp or Smalltalk, and I admit that”

Higher order functions

Higher order functions

Do one or more of the following:● Accept a function as an argument● Return a function as the return value

Higher order functions

Ruby introduces blocks, procs and lambdas as an instrument for higher order functions

[2, 3, 1].sort { |x,y| y <=> x }

higher_order_functions.rb

Time to code

Higher order functions

● map, select, inject, reduce, etc.

Higher order functions

Prefer this:

result = ["abraham", "isaac", "jacob"].map do |name|

name.capitalizeend

Higher order functions

Over this:

result = []

["abraham", "isaac", "jacob"].each do |name|

result << name.capitalizeend

Schonfinkeling

Schonfinkeling

Is the technique of translating the evaluation of a function that takes multiple arguments into evaluating a sequence of functions, each with a single argument -- Wikipedia

f(x, y, z) = f’(x)(y)(z)

Moses Schonfinkel

Proc#schonfinkel (ruby 1.9)

calc = proc { |op, a, b| a.send(op,

b) }

Schonfinkeling

Proc#schonfinkel (ruby 1.9)

calc = proc { |op, a, b| a.send(op,

b) }

add = calc.schonfinkel.(:+)

sub = calc.schonfinkel.(:-)

mult = calc.schonfinkel.(:*)

Schonfinkeling

Haskell Brooks Curry

Currying

Is the technique of translating the evaluation of a function that takes multiple arguments into evaluating a sequence of functions, each with a single argument -- Wikipedia

f(x, y, z) = f’(x)(y)(z)

Currying

Proc#curry (ruby 1.9)

calc = proc { |op, a, b| a.send(op,

b) }

add = calc.curry.(:+)

sub = calc.curry.(:-)

mult = calc.curry.(:*)

curry.rb

Time to code

and side effect free function

Immutability

Immutability

Imperative programming:A programming paradigm that describes computation in terms of statements that change a program state

Immutability

● Data is immutable (cannot be changed)● Everything is stateless

● Output depends only on input (no state)● Will always have the same output for the

same input● No side effect● Memoization● Idempotence

Immutability (pure functions)

● Parallelize● Concurrency● result = f(a) + f(b) # can be parallelized● Testing is easier

Immutability (pure functions)

immutability.rb

Time to code

Immutability

Prefer this:new_options = options.merge({key: value})

Over this:options.merge!({key: value})

Always prefer not to use the bang (!) version of a function

Memoization

Memoization

Pure functions always return the same output for the same input

No need to re-compute on every call

Memoization

# simple memo we use all the time (||=)

def fact(fact_id)

@fact[fact_id] ||= fetch_fact_from_db(fact_id)end

memoization.rb

Time to code

Tail call optimization

Recursion

Immutable data! how do we loop ?!We cannot do this:

i = 0 while i < 10

i = i + 1end(and we shouldn’t - this is ugly)

Recursion

Recursion

def factorial(n)

n < 2 ? 1 : n * factorial(n-1)end

factorial 10000 # stack level too deep

Recursion

def tail_factorial(n, r)

n < 2 ? r : tail_factorial(n-1, n*r)end

tail_factorial 10000 # OK (if tco enabled in ruby)

Recursion

# enable tail call

optimizationRubyVM::InstructionSequence.compile_option = {

:tailcall_optimization => true,

:trace_instruction => false

}

recursion.rb

Time to code

Enumerators

Enumerators

What is the sum of the first 10 numbers divided by 3?

Enumerators

# imperative - focuses on 'how'

count = 0; sum = 0; i = 0while count < 10

if i % 3 == 0

sum += i

count += 1

end

i += 1end

puts sum# functional (using enumerators) - focuses on 'what'

(0..10000).select { |x| x%3 == 0 }.take(10).reduce(:+)

Enumerators

select, each, inject, etc.. All use enumerators:[1, 2, 3].select.class => # enum

Enumerators

If you implement Enumerable in your class, you will have the following methods out of the box:● select● inject● take● etc.

enumerators.rb

Time to code

Laziness

Laziness

What is the sum of the first N numbers divided by 3?(0..Float::INFINITY).select { |x| x%3 == 0 }.take(N).reduce(:+)

Note: Only Chuck Norris can run this

Laziness

What is the sum of the first N numbers divided by 3?(0..Float::INFINITY).lazy.select { |x| x%3 == 0 }.take(N).reduce(:+)

Enumerator#Lazy introduced in Ruby 2.0

lazy.rb

Time to code

log_parser.rb

Log parser

Homoiconicity

Code is data, data is code

Homoiconicity

@chenfisher

Thanks!

code can be found here: https://github.com/chenfisher/functional-programming-with-ruby

top related