as defined by wikipedia
The borrowing of functional programming concepts into multiparadigm programming languages.
For a given set of inputs (x), a function always returns the same output (y).
f(x) => y
Ancient Greece - 17th century
In mathematics, a function is a relation between a set of inputs and a set of permissible outputs with the property that each input is related to exactly one output.
f(x) => y
For a given set of inputs (x), a function (f) always returns the same output (y).
1936
Created by Alonzo Church in 1936,
it is a formal system for expressing computation based on function abstraction and application.
f·g·x
(the application of `x` to the function `g` the result of which is applied to the function `f`)
1950's - Present
Lisp
Scheme
Scala
Clojure
OCaml
Haskell
F#
XQuery
SQL
JavaScript
Ruby
Java8
Python
Perl
C#
see what i did there?
let add1 = (x) => x + 1;
(fn) => fn();
(dis, dat) => dis(dat);
let x = add1(1) = 2;
function fn(x) { x ? fn(x-1) : x }
OOP combines data (properties) and associated behavior (methods) into a single location (an “object”).
FP moves data through functions which produce the effect of behavior.
class Pizza {
constructor(toppings=[]) {
this.toppings = toppings; //data
}
addToppings(toppings) { //behavior
for (topping of toppings) {
this.toppings.push(topping);
}
}
}
const pizza = { //data
toppings: []
};
//behavior
const addToppings = (toppings, dish) => ({
...dish,
toppings: [...dish.toppings, ...toppings]
});
OOP tends to be imperative -- describing how --, more domain specific and stateful
FP tends to be declarative in nature -- describing what --, more abstract and stateless.
class Pizza {
constructor(toppings=[]) {
this.toppings = toppings;
}
addToppings(toppings) {
for (topping of toppings) {
this.toppings.push(topping);
}
}
}
const pizza = new Pizza();
pizza.addToppings(['pepperoni'])
const pizza = {
toppings: []
};
const addToppings = (toppings, dish) => ({
...dish,
toppings: [...dish.toppings, ...toppings]
});
addToppings(['pepperoni'], pizza);
OOP views applications as collection of object models and how they relate to each other.
FP views applications as an orchestration of data transformations.
Food
-Desert
- Pie
- Pizza
pizza ->
makeDough ->
applySause ->
addToppings ->
bake
Functional programming is a paradigm shift from OOP. As with any paradigm shift, if one attempts to bring preconceptions from a previous paradigm, one's experience in the new paradigm will be less than satisfactory.
When starting out in a new paradigm, be prepared to challenge preconceptions. Have an open mind and try to go with the grain of the paradigm as much as possible.
My experience with functional style programming is that it won't make a whole lot of sense until you force yourself to fully embrace it.
When starting, expect to take several times longer to accomplish your goal that it would have otherwise.
How long did it take you to iterate through a list on day one. All the little micro patterns and practices you have built over the years you hadn't obtained yet. Don't expect shortcuts.
Expect that the amount of code you produce to be disproportionately small compared to the amount of time you spend on it. This can initially feel like you are not being productive. Functional code tends to be terse, yet expressive. There also tends to be fewer bugs in the code that need to be addressed after.
In functional style programming, functions are first class citizens, meaning functions can be used the same as any other reference. They can be assigned to variables, they can be passed as arguments or they can be returned as values from other functions.
The concept of higher order functions is closely related to the functions as first class citizens.
A function is a higher order function if:
Higher order functions form the foundations of functional style programming.
They can be used to "customize" a generic function.
const isNamed = (name) => (item) => item.name === name;
const isNamedCory = isNamed('Cory');
higher order function because...
it returns a function
They can abstract a pattern of processing.
const filter = (how, what) => let filtered = []; for (item of what) { filtered = how(item) ? [...filtered, item] : filtered; } return filtered;
filter(isNamedCory, ['Cory', 'Jared', 'Matt']);
higher order because it accepts a function.
They can compose other functions together.
const compose = (...fns) => (val) => fns.reduce( (v, f) => f(v), val );
const app = compose(fn1, fn2, fn3);
app(initialState);
higher order because it accepts and returns functions
classical vs functional examples.
Let's group our movies by genre
Think about the problem set, rather than the problem itself.
What are you doing to the data?
Have you done similar things in other scenarios?
How can those similar problems be universally described with functions?
Another way to think functionally is to start with your whole problem set as one unit. Then subdivide that unit into discrete smaller units at the same abstraction level.
Keep doing this until you have atomic functions. Functions that cannot be broken into more discrete pieces of functionality.
You have just deconstructed a functional solution. :)