const assert = (pred, desc, testing=true) =>
testing ? console.log(pred ? desc + 'passed! ' : desc + 'failure...')
: ""
// USAGE
const calculated = {a:1, b:2}
assert(R.equals({a:1, b:2}, calculated), "Simple peeps Test: ")
"Simple peeps Test: passed!"
const square = x => x * x
const addTwelve = x => x + 12
const peeps = [13, 42, 666]
//-------SIMPLE---------
const tight = peeps.map(x => square(x+12))
const expressive = peeps.map( function add12 (x) {return x + 12} )
.map( square )
//-------LIFTED-----
const peepsOut = peeps.map(Debug.lift)
.map(x => x.map( function add12 (y) {return y + 12} )
.map( square )
.run())
//peepOut returns:
[
{
contexts: {
add12: 25,
square: 625
},
current: 625,
init: 13
},
{
contexts: {
add12: 54,
square: 2916
},
current: 2916,
init: 42
},
{
contexts: {
add12: 678,
square: 459684
},
current: 459684,
init: 666
}
]
const expectedPeepsValues = [625, 2916, 459684]
const expectedPeepsFnResults = [
{
add12: 25,
square: 625
},
{
add12: 54,
square: 2916
},
{
add12: 678,
square: 459684
}
]
// performance example, dom example
const peepsOut = peeps.map(Debug.lift)
.map(x=> x.map( function add12 (y) {return y + 12} )
.map( square )
.run().contexts)
// INPUT -> peeps = [13,42,666]
const expectedPeepsValues = [625, 2916, 459684]
const expectedPeepsFnResults = [
{
add12: 25,
square: 625
},
{
add12: 54,
square: 2916
},
{
add12: 678,
square: 459684
}
]
//--------------TESTS-----------//
assert(R.equals(expressive, expectedPeepsValues), "Simple peeps Test: ")
assert(R.equals(expectedPeepsFnResults, peepsOut)
|| R.equals(expectedPeepsValues, peepsOut), "Complex peeps Test: ")
peepsOut
//--------------Using Reduction Instead of map-------------//
const funcs = [ function add12 (y) {return y + 12},
square
]
const start = peeps.map( x => funcs.reduce((current, fn)=>current.map(fn), Debug.lift(x)))
assert(R.equals(expectedPeepsFns, start.map(x=>x.run().context))
|| R.equals(expectedPeepsValues, start.map(x=>x.run().current)), "Refactored peeps Test: ")
start.map(x=>x.run())
peepsOut
/***********************************************************************************************
* Debug Class encapsulates *
* init : initial conditions, *
* current : current state, *
* contexts : state after function call *
* *
* Debug.lift:: a -> {init: a, current: a, contexts: {}} *
* Debug.from:: {init: a, current: a, contexts: {}} *
* -> {init: a, current: a, contexts: {}} *
* Debug.map :: (Debug a) => a -> fn -> { init: a.init, *
* current : fn(a.current), *
* contexts: (a.contexts.concat(fn.name:fn(a.current)} *
***********************************************************************************************/
class Debug {
constructor(struct) {
this.d = struct;
}
static lift = (a) => new Debug({contexts: {}, current: a, init: a})
static of = (a) => new Debug({contexts: {}, current: a, init: a});
static from = (a) => new Debug(a);
map = (fn) => Debug.from({
contexts: {...this.d.contexts, [fn.name]:fn(this.d.current)},
current : fn(this.d.current),
init : this.d.init
});
render = () => `${this.pp(this.d.contexts)} => ${this.d.current} ...from: ${JSON.stringify(this.d.init)}`
run = () => this.d;
pp = (obj) =>{
let txt = []
for (var x in obj) {
txt.push(`${x}: ${obj[x]}`)
}
return txt.join(", ")
}
}