Maximizing Efficiency and Profitability with OnePlan’s Professional Service A...
Basics of Functional Programming
1. Functional
Programming
• Functional code is characterised by one thing: the absence of side effects. It
doesn’t rely on data outside the current function, and it doesn’t change data that
exists outside the current function. Every other “functional” thing can be derived
from this property. Any examples of functions with side effects and no side
effects?
• The key to Functional Programming is in the name: functions. FP is about
immutability and composing functions rather than objects.
3. Functions are first class
• What makes something first class?
• It can be created on demand
• It can be stored in a data structure
• It can be passed as an argument to a function
• It can be returned as the value of a function
4. Creating functions on
demand using composition
Find the fifth element of a collection:
(def fifth (comp first rest rest rest rest))
(fifth [1 2 3 4 5])
•comp : Takes a set of functions and returns a fn that is the
composition of those fns
•first: Returns the first item in the collection
•rest: Returns a possibly empty seq of the items after the first.
•Find nth element of a collection using composition?
5. CREATING FUNCTIONS ON DEMAND USING
PARTIAL FUNCTIONS
((partial + 5) 100 200)
;=> 305
The function partial builds a new function that partially applies the single
argument 5 to the addition function. When the returned partial function is passed
the arguments 100 and 200, the result is their summation plus that of the value 5
captured by partial.
•
6. USING FUNCTIONS AS DATA
• First-class functions can not only be treated as data; they are data
• It can be stored in a container expecting a piece of data, be it a local, a
reference, collections, or anything able to store a
java.lang.Object.
(defn join
{:test (fn []
(assert
(= (join "," [1 2 3]) "1,3,3")))}
[sep s]
(apply str (interpose sep s)))
•
7. Higher-order functions
A higher-order function is a function that does at
least one of the following:
• Takes one or more functions as arguments
• Returns a function as a result
9. Functions as return values
•(complement f)
Takes a fn f and returns a fn that takes the same
arguments as f,
has the same effects, if any, and returns the opposite
truth value.
(def not-empty? (complement empty?))
;; #'user/not-empty?
10. Pure Functions
Simply put, pure functions are regular functions that, through
convention, conform to the following simple guidelines
• The function always returns the same result, given the same
arguments.
• The function doesn’t cause any observable side effects.
11. Pure or Impure?
var x = 5;
function addToX(a) {
return a + x;
}
function getLength(array) {
return array.length;
}
•
12. Pure or Impure?
function add(x, y) {
return x + y;
}
function add(x,y) {
updateDatabase();
return x + y;
}
•
13. REFERENTIAL TRANSPARENCY
TESTABILITY
If a function is referentially transparent, then it’s easier to reason about and
therefore more straightforward to test. Imagine the confusion should you add
further impure functions based on further external transient values.
OPTIMIZATION
If a function is referentially transparent, then it can more easily be optimized using
techniques such as memoization.
14. OOPS vs FP
Object-oriented programming (OOP) is a programming paradigm based on
the concept of "objects", which are data structures that contain data, in the
form of fields, often known as attributes; and code, in the form of procedures,
often known as methods
Functional programming is a programming paradigm, a style of building the
structure and elements of computer programs, that treats computation as the
evaluation of mathematical functions and avoids changing-state and mutable
data
15. OOP vs FP
the data (the stuff a program knows)
the behaviors (the stuff a program can do to/with that data)
•OOP says that bringing together data and its associated behavior in a
single location (called an “object”) makes it easier to understand how a
program works.
•FP says that data and behavior are distinctively different things and
should be kept separate for clarity.
16. Let’s say you run a company and you’ve just decided to
give all your employees a $10,000.00 raise. How could
we write a command-line script to make this change?
17. Approach using OOP
class Employee
def initialize(name, salary)
@name = name
@salary = salary
end
def change_salary(amt)
@salary = @salary + amt
end
def description
"#{@name} makes #{@salary}"
end
end
•
18. employees = [
Employee.new("Bob", 100000.0),
Employee.new("Jane", 125000.0)
]
Each Employee.new(...) call creates an object with data (@name and @salary) and
behavior (change_salary and description)
employees.each do |emp|
emp.change_salary(10000.0)
end
•
19. employees.each do |emp|
emp.change_salary(10000.0)
end
We call the “change_salary” method we defined in our class, passing in a value
of 10000.0.
This adds our $10K to the employee’s salary and stores the sum in @salary,
overwriting the existing value
The description method to build our output string instead of trying to access the
data fields (@salary and @name) directly. This is called “data hiding” and it
allows us to change the names of our instance variables without forcing the
users of our object to change how they use it.
20. FP Approach
employees = [
[ "Bob", 100000.0 ],
[ "Jane", 125000.0 ]
]
Instead of converting the data to an object and then calling methods on it, we
write a pair of standalone methods called change_salaries (plural) and
change_salary (singular)
we write a pair of standalone methods called change_salaries (plural) and
change_salary (singular). We pass change_salaries two arguments: the array
of arrays representing our data and the change amount. change_salaries
uses map instead of the each method we used in the OOP version
•
21. FP Approach
happier_employees = change_salaries(employees,
10000.0)
Because we don’t have objects, change_salaries requires that
we pass in not just the amount, but also the data we want to
modify.
22. FP Approach
happier_employees.each do |emp|
puts "#{emp[0]} makes #{emp[1]}"
end
Finally, we use ‘each’ to walk through every record in happier_employees and generate
the output message ourselves. This fits the FP model because FP likes to view
everything as a data transformation: you start with this dataset, apply these
transformations to it (in this case, adding $10K) and generate a new dataset
Another subtle -- but important -- difference is that in the OOP version change_salary
used each to process each employee, but the FP version uses map. Instead of
changing the original value, ’map’ creates a copy of the array containing the return value
of each pass. When all elements have been processed, map hands us the copy with all
the new values, which we store in happier_employees. The original array is untouched!
This idea of not changing the contents (or “state”) of a variable once it’s been created is
called immutability and is another key aspect of FP. Before and After state.