Last active
April 3, 2025 06:07
-
-
Save Muzietto/336141ccf57469bcd652c77df13a625c to your computer and use it in GitHub Desktop.
Recur or Perish
This file contains hidden or 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
// EXPERIMENTAL STUFF (not working) - tests are failing | |
// truly recursive drill down for arrays | |
export const dda = pos => ctx => visitor => { | |
console.log('pos', pos); | |
console.log('ctx', ctx); | |
console.log('visitor', visitor); | |
return [ | |
...ctx.slice(0, pos), | |
visitor(), | |
...ctx.slice(pos + 1) | |
]; | |
} | |
// WORKING STUFF - tests are ok | |
// drilldown in array | |
export function ddArray(ctx, pos) { | |
// console.log('aaa2', ctx, pos); | |
return visitor => [ | |
...ctx.slice(0, pos), | |
visitor(), | |
...ctx.slice(pos + 1) | |
]; | |
} | |
// drilldown in object | |
export function ddObject(ctx, key) { | |
return (visitor, swapKey) => { | |
// console.log('swapKey=', !!swapKey); | |
return !swapKey | |
? { | |
...ctx, | |
[key]: visitor(), | |
} | |
: Object.keys(ctx).reduce( | |
(acc, curr) => | |
curr !== key | |
? { ...acc, [curr]: ctx[curr] } | |
: { ...acc, [visitor()]: ctx[key] }, | |
{}, | |
); | |
}; | |
} | |
// returns an array without an element or an object without a keyvalue | |
export function removed(ctx) { // ctx = valore, see JSObject/JSArray - remover={r => returner(() => removed(valore)(r))} | |
return keyF => { // see Transformed - const newCurrentValue = remover(() => chiave); | |
const key = keyF(); | |
if (ctx.length && ctx.slice) { | |
console.log('removing from array'); | |
return [...ctx.slice(0, key), ...ctx.slice(key + 1)]; | |
} | |
console.log('removing from object'); | |
return Object.keys(ctx).reduce( | |
(acc, curr) => | |
(curr !== key) | |
? { ...acc, [curr]: ctx[curr] } | |
: acc, | |
{}, | |
); | |
} | |
} | |
// returns an array with an added element or an object with an added keyvalue | |
export function added(ctx) { // ctx = valore, see JSObject/JSArray - adder={r => returner(() => added(valore)(r))} | |
return keyF => { // see Transformed - const newCurrentValue = adder(() => thingToAdd); | |
const thingToAdd = keyF(); | |
console.log('added - ctx is', ctx) | |
if (ctx.length && ctx.slice) { | |
console.log('adding to array', thingToAdd); | |
return [...ctx, thingToAdd]; // always at the end | |
} | |
console.log('adding to object', thingToAdd); | |
return { | |
...ctx, | |
...thingToAdd, // gotta ensure it's an object | |
}; | |
} | |
} | |
// utils stuff | |
export function isObject(valore) { | |
return (typeof valore === 'object') && !Array.isArray(valore); | |
} | |
export function isArray(valore) { | |
return Array.isArray(valore); | |
} | |
export function isBoolean(valore) { | |
return (typeof valore === 'boolean'); | |
} | |
export function isString(valore) { | |
return typeof valore === 'string'; | |
} | |
export function isNumber(valore) { | |
return typeof valore === 'number'; | |
} | |
export function whatTypeIs(valore) { | |
if (isObject(valore)) return 'object'; | |
if (isArray(valore)) return 'array'; | |
if (isBoolean(valore)) return 'boolean'; | |
if (isString(valore)) return 'string'; | |
if (isNumber(valore)) return 'number'; | |
} | |
export function isArrayIndex(chiave) { | |
return [...Array(101).keys()] | |
.map(c => c + '') | |
.includes(chiave + ''); | |
} |
This file contains hidden or 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
import { | |
ddArray, | |
ddObject, | |
added, | |
removed, | |
dda, | |
} from './traverser'; | |
describe('in the implemented world', () => { | |
describe('ddArray drills down an array', () => { | |
it('very shallow', () => { | |
const returner0 = r => ddArray(['a', 'b'], 0)(r); | |
const result0 = returner0(() => 'ciao'); | |
expect(result0).toEqual(['ciao', 'b']); | |
const returner1 = r => ddArray(['a', 'b'], 1)(r); | |
const result1 = returner1(() => 'ciao'); | |
expect(result1).toEqual(['a', 'ciao']); | |
}); | |
it('a little bit deeper', () => { | |
const returner1 = r => ddArray(['a', 'b', [0, 1]], 2)(r); | |
const returner2 = r => returner1(() => ddArray([0, 1], 0)(r)); // this is wasteful - we shouldn't have to express [0,1] ourselves !!! | |
const result = returner2(() => 'ciao'); | |
expect(result).toEqual(['a', 'b', ['ciao', 1]]); | |
}); | |
it('a lot deeper', () => { | |
const returner1 = r => ddArray(['a', 'b', [0, [1]]], 2)(r); | |
const returner2 = r => returner1(() => ddArray([0, [1]], 1)(r)); // this is wasteful | |
const returner3 = r => returner2(() => ddArray([1], 0)(r)); // this is wasteful | |
const result = returner3(() => 'ciao'); | |
expect(result).toEqual(['a', 'b', [0, ['ciao']]]); | |
}); | |
}); | |
describe('ddObject drills down an object', () => { | |
it('very shallow', () => { | |
const returner0 = r => ddObject({ qwe: 'a', wer: 'b' }, 'qwe')(r); | |
const result0 = returner0(() => 'ciao'); | |
expect(result0).toEqual({ qwe: 'ciao', wer: 'b' }); | |
const returner1 = r => ddObject({ qwe: 'a', wer: 'b' }, 'wer')(r); | |
const result1 = returner1(() => 'ciao'); | |
expect(result1).toEqual({ wer: 'ciao', qwe: 'a' }); | |
}); | |
it('a little bit deeper', () => { | |
const returner1 = r => ddObject({ qwe: 'a', wer: { asd: 'b' } }, 'wer')(r); | |
const returner2 = r => returner1(() => ddObject({ asd: 'b' }, 'asd')(r)); // this is wasteful | |
const result = returner2(() => 'ciao'); | |
expect(result).toEqual({ qwe: 'a', wer: { asd: 'ciao' } }); | |
}); | |
it('a lot deeper', () => { | |
const returner1 = r => ddObject({ qwe: 'a', wer: { asd: { tyu: 'b' } } }, 'wer')(r); | |
const returner2 = r => returner1(() => ddObject({ asd: { tyu: 'b' } }, 'asd')(r)); // this is wasteful | |
const returner3 = r => returner2(() => ddObject({ tyu: 'b' }, 'tyu')(r)); // this is wasteful | |
const result = returner3(() => 'ciao'); | |
expect(result).toEqual({ qwe: 'a', wer: { asd: { tyu: 'ciao' } } }); | |
}); | |
}); | |
describe('ddArray and ddObject work together', () => { | |
it('in a simple example', () => { | |
const returner0 = r => ddObject({ qwe: 'a', wer: ['b', 'c'] }, 'wer')(r); | |
const returner1 = r => returner0(() => ddArray(['b', 'c'], 0)(r)); // this is wasteful | |
const result1 = returner1(() => 'ciao'); | |
expect(result1).toEqual({ qwe: 'a', wer: ['ciao', 'c'] }); | |
}); | |
it('in a complex example', () => { | |
const returner0 = r => ddObject({ qwe: 'a', wer: ['b', { xcv: 123, ert: true }] }, 'wer')(r); | |
const returner1 = r => returner0(() => ddArray(['b', { xcv: 123, ert: true }], 1)(r)); // this is wasteful | |
const returner2 = r => returner1(() => ddObject({ xcv: 123, ert: true }, 'ert')(r)); // this is wasteful | |
const result1 = returner2(() => 'ciao'); | |
expect(result1).toEqual({ qwe: 'a', wer: ['b', { xcv: 123, ert: 'ciao' }] }); | |
}); | |
}); | |
describe('removed returns an array without an element or an object without a keyvalue', () => { | |
it('in a very shallow situation', () => { | |
const remover0 = () => removed(['a', 'b']) | |
const result0 = remover0()(() => 0); | |
expect(result0).toEqual(['b']); | |
const remover1 = () => removed({ qwe: 123, ert: 345 }) | |
const result1 = remover1()(() => 'ert'); | |
expect(result1).toEqual({ qwe: 123 }); | |
}); | |
it('in a less shallow situation', () => { | |
const returner0 = r => ddArray(['a', { qwe: 123, ert: 345 }], 1)(r); | |
const remover1 = r => returner0(() => removed({ qwe: 123, ert: 345 })(r)); // wasteful | |
const result1 = remover1(() => 'qwe'); | |
expect(result1).toEqual(['a', { ert: 345 }]); | |
}); | |
it('in a deep situation', () => { | |
const returner0 = r => ddArray(['a', { qwe: 123, ert: [234, true] }], 1)(r); | |
const returner1 = r => returner0(() => ddObject({ qwe: 123, ert: [234, true] }, 'ert')(r)); // this is wasteful | |
const remover2 = r => returner1(() => removed([234, true])(r)); // wasteful | |
const result2 = remover2(() => 1); | |
expect(result2).toEqual(['a', { qwe: 123, ert: [234] }]); | |
const returner00 = r => ddArray(['a', { qwe: 123, ert: [234, true] }], 1)(r); | |
const remover01 = r => returner00(() => removed({ qwe: 123, ert: [234, true] })(r)); // wasteful | |
const result21 = remover01(() => 'ert'); | |
expect(result21).toEqual(['a', { qwe: 123 }]); | |
}); | |
}); | |
describe('added returns an array with an added element or an object with an added keyvalue', () => { | |
it('in a very shallow situation', () => { | |
const adder0 = () => added(['a', 'b']) | |
const result0 = adder0()(() => 'c'); | |
expect(result0).toEqual(['a', 'b', 'c']); | |
const adder1 = added({ qwe: 123, ert: 345 }) | |
const result1 = adder1(() => ({ rty: 567 })); | |
expect(result1).toEqual({ qwe: 123, ert: 345, rty: 567 }); | |
}); | |
it('in a less shallow situation', () => { | |
const returner0 = r => ddArray(['a', { qwe: 123, ert: 345 }], 1)(r); | |
const adder1 = r => returner0(() => added({ qwe: 123, ert: 345 })(r)); // wasteful | |
const result1 = adder1(() => ({ rty: 567 })); | |
expect(result1).toEqual(['a', { qwe: 123, ert: 345, rty: 567 }]); | |
}); | |
it('in a deep situation', () => { | |
const returner0 = r => ddArray(['a', { qwe: 123, ert: [234, true] }], 1)(r); | |
const returner1 = r => returner0(() => ddObject({ qwe: 123, ert: [234, true] }, 'ert')(r)); // this is wasteful | |
const adder2 = r => returner1(() => added([234, true])(r)); // wasteful | |
const result2 = adder2(() => 1); | |
expect(result2).toEqual(['a', { qwe: 123, ert: [234, true, 1] }]); | |
const returner00 = r => ddArray(['a', { qwe: 123, ert: [234, true] }], 1)(r); | |
const adder01 = r => returner00(() => added({ qwe: 123, ert: [234, true] })(r)); // wasteful | |
const result21 = adder01(() => ({ rty: false })); | |
expect(result21).toEqual(['a', { qwe: 123, ert: [234, true], rty: false }]); | |
}); | |
}); | |
}); | |
xdescribe('in the still experimental world', () => { | |
describe('dda drills down an array with REALLY recursively built context', () => { | |
xit('very shallow', () => { // this test works, but it is too simple to express a true drilldown | |
const returner0 = dda(0)(['a', 'b']); | |
const result0 = returner0(() => 'ciao'); | |
expect(result0).toEqual(['ciao', 'b']); | |
}); | |
it('a little bit deeper', () => { | |
// const contexter1 = dda(2)(['a', 'b', [0, 1]]); // visitor => result | |
// const returner2 = v => dda(0)(contexter1(v)); | |
const returner1 = dda(2)(['a', 'b', [0, 1]]); // visitor => result | |
const returner2 = r => returner1(() => dda(0)(c)(r)); | |
const result = returner2(() => 'ciao'); | |
expect(result).toEqual(['a', 'b', ['ciao', 1]]); | |
}); | |
}); | |
}); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Inside the traverser.js library, methods ddArray and ddObject are wasteful, because they require to express the context in which they operate at each recursion level. They are working anyhow, and their tests are described with "in the implemented world" in the specs file.
Specs file shows several usages of them in order to:
Method dda is an attempt to create a recursion that drills inside an array without any additional help, but it's not working. Related tests are described with "in the still experimental world".
the scope of this gist is to prepare: