GitHub - seanhess/functional-javascript: Functional Javascript: The Good Parts
source link: https://github.com/seanhess/functional-javascript
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
Functional Javascript: The Good Parts
Follow Along: https://github.com/seanhess/functional-javascript
Functional programming encourages us to organize our code well and helps us create code that is easier to reason about. The less we reinvent the wheel and use a well-tested tool, the easier it is to maintain our application code.
"Pure" functions return a result based only on what you pass in. You never have to worry it is going to do something unexpected. Higher order functions (functions that take other functions as parameters) let us reuse code in places we wouldn't expect, like loops. Composition allows you to create larger tools from smaller ones.
Javascript is a great functional language, but some ideas are harder to implement than others, and some aren't worth using in JS at all! After having wandered the Functional JS wastes for a few years, I will tell you stories of the dangers that lurk, as well as the rewards that await you if you apply Functional JS wisely.
About Me
Sean Hess
Programmer, Inventor, Startup Advisor. Solve hard problems, build productive teams. Kuali.co
What is Functional Programming?
In computer science, 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 state and mutable data. — Wikipedia
Wait, What?
The alternative: Imperative Programming
Series of instructions to the computer to access & modify memory.
// I understand how every line of this works!
var totalAge = 0
for (var i = 0; i < users.length; i++) {
totalAge += users[i].age
}
Functional Programming
Functions as high-level tools you combine to do something. Math!
// don't know how this works, but it's clear what it does
var totalAge = users.map(userAge).reduce(sum)
- 1930 Lambda Calculus
- 1958 Lisp and friends, John McCarthy
- 1977 FP and composition. John Backus
- 1978 ML
- 1987 Haskell
- 2004+ Scala, F#, Clojure
- 2010+ Popularity? [1]
Why functional programming?
What instead of How
Guarantees mean we can make nifty assumptions. Easier maintenance.
More code is reusable. Toolbox to Workshop
More expressive. Orders of magnitude smaller.
Tradeoffs: Bigger Vocabulary
Failing to convince people at I.TV
Tradeoffs: New Concepts
Learning languages is so easy. I speak both English and Pig latin! - Programmers
Concepts: Pure Functions
Elevate the pure functions from the impure, lest they drag your whole codebase into the mire. — Saint Curry (not the spice)
Pure functions return the same result given the same arguments. Calling them does not cause side effects like mutation or IO.
Example: Isaac Netwon
class Apple {
constructor(gravity) {
this.y = 0
this.gravity = -9.8
this.velocity = 0
}
// fall depends on this.gravity, and this.y, which can change.
// this is the right equation, I think...
// what happens if I call this twice?
fall(dt) {
this.y += this.gravity * dt
}
}
Separate out the pure calculation:
// look at this nice function I found on NPM!
// I guess my function was totally wrong
function doPhysics(a, v0, dt) {
return v0*dt + (a*dt^2)/2
}
var distance = doPhysics(apple.gravity, apple.velocity, dt)
apple.y += distance
Pure: Referential Transparency
The output is ONLY a function of the inputs. Swap it out.
- Optimizations - concurrency, memoization
- Easier to test and refactor
- Encourages reuse - independent of any classes (
Apple
vsfall
vsdoPhysics
)
Pure: No Side Effects
It doesn't mess anything else up. It won't change your arguments, global state, or the file system.
- Safe and Predictable - less brain space
Separate the Pure from the rest
You still need IO and have state. Find the pure calculations and keep them separate
Concepts: Higher Order Functions
Higher Order Functions take a function as a parameter, or return a function. They let us reuse code in places we wouldn't expect, like loops.
Example: Older is better
var bestProgrammer;
for (var i = 0; i < programmers.length; i++) {
if (!bestProgrammer || programmers[i].age > bestProgrammer.age) {
bestProgrammer = programmers[i]
}
}
What is reusable about the above? Everything but .age
.
function maximum(items, toValue) {
var maxItem
for (var i = 0; i < items.length; i++) {
if (!maxItem || toValue(items[i]) > toValue(maxItem)) {
maxItem = items[i]
}
}
return maxItem
}
The above belongs in an NPM module, and is no longer a part of our code base. POOF!
bestProgrammer = maximum(programmers, function(person) {
return person.age
})
// ES6 version
bestProgrammer = maximum(programmers, (person) => person.age)
This is much easier to read. Maximum
is most likely maintained by someone else in the community and becomes well-tested. We can forget about how it works.
See lodash.com for many common higher order functions.
Concepts: Composition
"I like tiny programs that do one thing well and one thing only. Which hypothetical reusable modules would make the task at hand trivial?" — substack
Build very focused tools, then use them to do something bigger. Here's our totalAge
code from before.
// Yay, I understand how every line of this works!
var totalAge = 0
for (var i = 0; i < users.length; i++) {
totalAge += users[i].age
}
First we need some new tools.
Array.map
converts each item in an array to something else:
[1,2,3].map(function(n) {
return n*2
})
// -> [2,4,6]
Array.reduce
aggregates data from an array into a single value
[1,2,3].reduce(function(total, n) {
return total + n
}, 0)
// -> 6
Let's make a sum
function, which does the same thing as +
. as well as a function that gives the users' age
function sum(a, b) { return a + b }
function getAge(object) { return object.age }
That's 4 new tools in our toolbox: map
, reduce
, sum
, and getAge
. With all 4 of these, our original code becomes trivial.
// don't know HOW this works, but it's clear WHAT it does
var totalAge = users.map(getAge).reduce(sum)
Our composed application code is very unlikely to be buggy. Any bugs are probably in the individual functions, most of which come from well-tested 3rd party libraries.
Principles
- do one thing, do it well
- most basic parameter possible
- someone already wrote it
Instead of Inheritance
Example: Front-end components
Composition-Driven Development
Start writing the application code as if the functions exist. Start with What. Go back and write the new tools you need later.
function solveWorldHunger(population) {
// hmm, this seems hard, but if I break it down...
var food = getSoylent(population * MUCHO)
var shipping = efficientDistribution(food)
var economy = fixWorldEconomy(Time.MaybeTomorrow)
return combine(shipping, economy)
}
Application Agnostic
What is reusable about your code but not specific to your application? Write it and be famous. Oh wait, someone already did.
Recompose to override things
3rd party libraries: make your most important calculations available as focused functions! You can't anticipate everything!
A map through the functional JS wastes
Consider using lambdas for clarity.
[1,2,3].map((n) => sum(n, 2)) // more clear
[1,2,3].map(sum.bind(null, 2)) // way too noisy
var sumc = _.curry(sum)
[1,2,3].map(sumc(2)) // confusing if people don't know about curry
The compose
function is not really worth the confusion. Just use lambdas.
function greet(name) {
return "Hello ", + name
}
function excitedly(message) {
return message+"!"
}
var welcome = _.compose(excitedly, greet) // what type is welcome?
var welcome = (name) => excitedly(greet(name)) // easier to understand
welcome("Kuali")
Crazy recursive loops
function eatAndDisgest(array) {
var item = array.pop()
return item + eatAndDisgest(array) // the stack hates you
}
Use a type system! Compose
We all Win
If we focus on composable code we can all build off each other's work.
What instead of How. Smaller code bases. Refactoring. Maintenance
It's Over!
github.com/seanhess/functional-javascript
Contact Me: @seanhess
Recommend
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK