May 28, 2014
This code is a companion to the APIcon presentation Real-World Functional Programming by @jearldouglas and @kelleyrobinson. The slides are available here.
In this code, we compare imperative and functional implementations of a withdraw
function that might be used in a banking ATM.
In a conventionally imperative style, a withdraw
function might:
- Take an
amount
argument - Look up an external
balance
- Decrease the external
balance
byamount
- Return
amount
function withdraw(amount) {
if (balance >= amount) {
balance = balance - amount
return amount
} else {
return 0
}
}
The big problem with this implementation is its dependence on an out-of-context balance
that it both accesses and mutates.
In a functional style, a withdraw
function might instead:
- Take an
amount
argument - Return a new function that itself takes a
balance
argument, and: - Computes the new
balance
without modifying the incoming one - Returns both the new
balance
andamount
function withdraw(amount) {
return function(balance) {
if (balance >= amount) {
return [amount, balance - amount]
} else {
return [0, balance]
}
}
}
The main advantage of this is that withdraw
can be executed, e.g. withdraw(20)
, without any triggering any interaction with a balance
(external or otherwise). This leaves us free to take the resulting callback and do other things with it (e.g. compose it with other callbacks, map over it, bind it to other callback-returning functions, or simply run it with an immutable balance
argument).
To run each example, use node <filename.js>
:
$ node imperative.js
old balance: ???
amount withdrawn: 20
new balance: 10
$ node functional.js
old balance: 30
amount withdrawn: 20
new balance: 10
old balance: 10
amount withdrawn: 0
new balance: 10
$ node functional-composition.js
old balance: 30
amount withdrawn: 25
new balance: 5
old balance: 22
amount withdrawn: 20
new balance: 2
$ node functional-mapping.js
old balance: 30
amount withdrawn: 0.034782608695652174
new balance: 10
$ node functional-binding.js
old balance: 30
amount withdrawn: 0.034782608695652174
new balance: 9.8