Created
May 17, 2018 11:39
-
-
Save AKJAW/9b7fe4f13c1c79f01470a9077ea112f4 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
c = console.log | |
//Mathematical Idempotence | |
function toPower0(x) { | |
return Math.pow( x, 0 ); | |
} | |
function snapUp3(x) { | |
return x - (x % 3) + (x % 3 > 0 && 3); | |
} | |
toPower0( 3 ) == toPower0( toPower0( 3 ) ); // true | |
snapUp3( 3.14 ) == snapUp3( snapUp3( 3.14 ) ); // true | |
var x = 42, y = "hello"; | |
String( x ) === String( String( x ) ); // true | |
Boolean( y ) === Boolean( Boolean( y ) ); // true | |
function upper(x) { | |
return x.toUpperCase(); | |
} | |
function lower(x) { | |
return x.toLowerCase(); | |
} | |
var str = "Hello World"; | |
upper( str ) == upper( upper( str ) ); // true | |
lower( str ) == lower( lower( str ) ); // true | |
function currency(val) { | |
var num = parseFloat( | |
String( val ).replace( /[^\d.-]+/g, "" ) | |
); | |
var sign = (num < 0) ? "-" : ""; | |
return `${sign}$${Math.abs( num ).toFixed( 2 )}`; | |
} | |
currency( -3.1 ); // "-$3.10" | |
currency( -3.1 ) == currency( currency( -3.1 ) ); // true | |
//Programming Idempotence | |
var obj = {} | |
var a = [1] | |
var person = {name:'pawel'} | |
// idempotent: | |
obj.count = 2; | |
a[a.length - 1] = 42; | |
person.name = upper( person.name ); | |
// non-idempotent: | |
obj.count++; | |
a[a.length] = 42; | |
person.lastUpdated = Date.now(); | |
var hist = document.getElementById( "orderHistory" ); | |
var order = {latestUpdate: 1} | |
// idempotent: | |
hist.innerHTML = order.historyText; | |
// non-idempotent: | |
var update = document.createTextNode( order.latestUpdate ); | |
hist.appendChild( update ); | |
//Purely Relative | |
function rememberNumbers(nums) { | |
return function caller(fn){ | |
return fn( nums ); | |
}; | |
} | |
var list = [1,2,3,4,5]; | |
var simpleList = rememberNumbers( list ); | |
function median(nums) { | |
return (nums[0] + nums[nums.length - 1]) / 2; | |
} | |
//c(simpleList( median )); // 3 | |
// .. | |
list.push( 6 ); | |
// .. | |
//c(simpleList( median )); // 3.5 | |
//NAPRAWA | |
//tworzymy kopie parametru | |
function rememberNumbers(nums) { | |
// make a copy of the array | |
nums = [...nums]; | |
return function caller(fn){ | |
return fn( nums ); | |
}; | |
} | |
var list = [1,2,3,4,5]; | |
var simpleList = rememberNumbers( list ); | |
// yes, a silly contrived example :) | |
function firstValue(nums) { | |
return nums[0]; | |
} | |
function lastValue(nums) { | |
return firstValue( nums.reverse() ); | |
} | |
//c(simpleList( lastValue )); // 5 | |
//c(list); // [1,2,3,4,5] -- OK! | |
//c(simpleList( lastValue )); // 1 | |
function rememberNumbers(nums) { | |
return function caller(fn){ | |
// send in a copy! | |
return fn( [...nums] ); | |
}; | |
} | |
var list = [1,2,3,4,5]; | |
var simpleList = rememberNumbers( list ); | |
//c(simpleList( lastValue )); // 5 | |
//c(list); // [1,2,3,4,5] -- OK! | |
//c(simpleList( lastValue )); // 5 | |
simpleList( function impureIO(nums){ | |
//c( nums.length ); //5 | |
} ); | |
//Performance Effects | |
var cache = []; | |
function specialNumber(n) { | |
// if we've already calculated this special number, | |
// skip the work and just return it from the cache | |
if (cache[n] !== undefined) { | |
return cache[n]; | |
} | |
var x = 1, y = 1; | |
for (let i = 1; i <= n; i++) { | |
x += i % 2; | |
y += i % 3; | |
} | |
cache[n] = (x * y) / (n + 1); | |
return cache[n]; | |
} | |
//specialNumber( 6 ); // 4 | |
//specialNumber( 42 ); // 22 | |
//specialNumber( 1E6 ); // 500001 | |
//specialNumber( 987654321 ); // 493827162 | |
//memoizacja | |
var specialNumber = (function memoization(){ | |
var cache = []; | |
return function specialNumber(n){ | |
// if we've already calculated this special number, | |
// skip the work and just return it from the cache | |
if (cache[n] !== undefined) { | |
return cache[n]; | |
} | |
var x = 1, y = 1; | |
for (let i = 1; i <= n; i++) { | |
x += i % 2; | |
y += i % 3; | |
} | |
cache[n] = (x * y) / (n + 1); | |
return cache[n]; | |
}; | |
})(); | |
//Purifying zwiekszenie widocznosci efektow ubocznych | |
function addMaxNum(arr) { | |
var maxNum = Math.max( ...arr ); | |
arr.push( maxNum + 1 ); | |
} | |
var nums = [4,2,7,3]; | |
addMaxNum( nums ); | |
nums; // [4,2,7,3,8] | |
//=> | |
function addMaxNum(arr) { | |
var maxNum = Math.max( ...arr ); | |
return maxNum + 1; | |
} | |
var nums = [4,2,7,3]; | |
nums.push( | |
addMaxNum( nums ) | |
); | |
nums; // [4,2,7,3,8] | |
//Containing Effects | |
var users = {}; | |
function fetchUserData(userId) { | |
ajax( `http://some.api/user/${userId}`, function onUserData(user){ | |
users[userId] = user; | |
} ); | |
} | |
//=> | |
function safer_fetchUserData(userId,users) { | |
// simple, naive ES6+ shallow object copy, could also | |
// be done w/ various libs or frameworks | |
users = Object.assign( {}, users ); | |
fetchUserData( userId ); | |
// return the copied state | |
return users; | |
// *********************** | |
// original untouched impure function: | |
function fetchUserData(userId) { | |
ajax( | |
`http://some.api/user/${userId}`, | |
function onUserData(user){ | |
users[userId] = user; | |
} | |
); | |
} | |
} | |
//Covering Up Effects -- only sync code | |
var nums = []; | |
var smallCount = 0; | |
var largeCount = 0; | |
function generateMoreRandoms(count) { | |
for (let i = 0; i < count; i++) { | |
let num = Math.random(); | |
if (num >= 0.5) { | |
largeCount++; | |
} | |
else { | |
smallCount++; | |
} | |
nums.push( num ); | |
} | |
} | |
function safer_generateMoreRandoms(count,initial) { | |
// (1) Save original state | |
var orig = { | |
nums, | |
smallCount, | |
largeCount | |
}; | |
// (2) Set up initial pre-side effects state | |
nums = [...initial.nums]; | |
smallCount = initial.smallCount; | |
largeCount = initial.largeCount; | |
// (3) Beware impurity! | |
generateMoreRandoms( count ); | |
// (4) Capture side effect state | |
var sides = { | |
nums, | |
smallCount, | |
largeCount | |
}; | |
// (5) Restore original state | |
nums = orig.nums; | |
smallCount = orig.smallCount; | |
largeCount = orig.largeCount; | |
// (6) Expose side effect state directly as output | |
return sides; | |
} | |
var initialStates = { | |
nums: [0.3, 0.4, 0.5], | |
smallCount: 2, | |
largeCount: 1 | |
}; | |
safer_generateMoreRandoms( 5, initialStates ); | |
// { nums: [0.3,0.4,0.5,0.8510024448959794,0.04206799238... | |
nums; // [] | |
smallCount; // 0 | |
largeCount; // 0 | |
//Evading Effects | |
function handleInactiveUsers(userList,dateCutoff) { | |
for (let i = 0; i < userList.length; i++) { | |
if (userList[i].lastLogin == null) { | |
// remove the user from the list | |
userList.splice( i, 1 ); | |
i--; | |
} | |
else if (userList[i].lastLogin < dateCutoff) { | |
userList[i].inactive = true; | |
} | |
} | |
} | |
function safer_handleInactiveUsers(userList,dateCutoff) { | |
// make a copy of both the list and its user objects | |
let copiedUserList = userList.map( function mapper(user){ | |
// copy a `user` object | |
return Object.assign( {}, user ); | |
} ); | |
// call the original function with the copy | |
handleInactiveUsers( copiedUserList, dateCutoff ); | |
// expose the mutated list as a direct output | |
return copiedUserList; | |
} | |
//this Revisited | |
var ids = { | |
prefix: "_", | |
generate() { | |
return this.prefix + Math.random(); | |
} | |
}; | |
function safer_generate(context) { | |
return ids.generate.call( context ); | |
} | |
// ********************* | |
safer_generate( { prefix: "foo" } ); | |
// "foo0.8988802158307285" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment