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
amountargument - Look up an external
balance - Decrease the external
balancebyamount - 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
amountargument - Return a new function that itself takes a
balanceargument, and: - Computes the new
balancewithout modifying the incoming one - Returns both the new
balanceandamount
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