Skip to content

Instantly share code, notes, and snippets.

@Tahseenm
Last active October 29, 2017 20:43
Show Gist options
  • Save Tahseenm/4bc023896bebc9d654fed44b5e4bf1f6 to your computer and use it in GitHub Desktop.
Save Tahseenm/4bc023896bebc9d654fed44b5e4bf1f6 to your computer and use it in GitHub Desktop.
Little Javascript Problem Solution
/* -------------------------------------------------------------------------- *\
* Solution
\* -------------------------------------------------------------------------- */
/** :: (val: any) -> boolean */
const isNull = val => val === null
/** :: (list: Function, start: number) -> Function */
const slice = (list, start = 0) => idx => list(idx + start)
/** :: (list: Function) -> number */
const length = list => (function getLen(list, len = 0) {
return isNull(list(0)) ? len : getLen(slice(list, 1), len + 1)
})(list)
/** :: (min: number, max: number) -> (idx: number) -> number | null */
const range = (min, max) => idx => (idx >= 0 && min + idx <= max) ? min + idx : null
/** :: (list: Function, iteratee: Function) -> Function */
const map = (list, fn) => idx => !isNull(list(idx)) ? fn(list(idx)) : null
/** :: (list: Function) -> Function */
const reverse = list => idx => list(length(list) - 1 - idx)
/** :: (list: Function, iteratee: Function) -> void */
const forEach = (list, iteratee) => {
if (isNull(list(0))) return
iteratee(list(0))
return forEach(slice(list, 1), iteratee)
}
/**
* Test :)
*/
const nums = reverse(map(range(1, 10), n => n ** 2))
forEach(nums, console.log)
/* -------------------------------------------------------------------------- *\
* Helpers
\* -------------------------------------------------------------------------- */
/** :: (val: any) -> boolean */
const isNull = val => val === null
/** :: (list: Function) -> number */
const first = list => list(0)
/** :: (list: Function, start: number?) -> Function */
const sliceFrom = (list, start = 0) =>
idx => list(idx + start)
/** :: (list: Function) -> number */
const length = list => (function getLength(list, len = 0) {
return isNull(first(list)) ? len : getLength(sliceFrom(list, 1), len + 1)
}(list))
/* -------------------------------------------------------------------------- *\
* An interesting Javascript Problem
\* -------------------------------------------------------------------------- */
/** :: (min: number, max: number) -> (idx: number) -> number | null */
const range = (min, max) =>
idx => idx >= 0 && (min + idx) <= max ? min + idx : null
/** :: (iteratee: Function) -> (list: Function) -> Function */
const map = iteratee => list =>
idx => !isNull(list(idx)) ? iteratee(list(idx)) : null
/** :: (list: Function) -> Function */
const reverse = list =>
idx => list(length(list) - 1 - idx)
/** :: (iteratee: Function) -> (list: Function) -> void */
const forEach = (iteratee) => (list) => {
if (isNull(first(list))) return
iteratee(first(list))
return forEach(iteratee)(sliceFrom(list, 1))
}
/** :: (f: Function, g: Function, h: Function) -> Function */
const pipe = (f, g, h) => (x, y) => h(g(f(x, y)))
/**
* Let's Test it !
*/
const printEach = forEach(console.log)
const nums = pipe(
range,
map(n => n ** 2),
reverse,
)(1, 10)
printEach(nums) /** Should Output:
* 100
* 81
* 64
* 49
* 36
* 25
* 16
* 9
* 4
* 1
*/
/* ------------------------------------------------------------------------------ *\
* Solution 2
\* ------------------------------------------------------------------------------ */
/**
* @param {number} min
* @param {number} min
* @returns {Function}
*
* @example
* const f = range(1, 3)
* f() // -> 1
* f() // -> 2
* f() // -> 3
* f() // -> null
* f() // -> 3
* ...
*/
const range = (min, max) => {
let cursor = min
let inc = true
const get = () => {
// Incrementing
if (inc) {
if (cursor > max) {
cursor = max
inc = false
return null
}
else return cursor++
}
// Decrementing
else {
if (cursor < min) {
cursor = min
inc = true
return null
}
else return cursor--
}
}
return get
}
const reverse = collection => collection() !== null ? reverse(collection) : collection
const forEach = (collection, iteratee) => {
for (let item = collection(); item !== null; item = collection())
iteratee(item)
}
const map = (collection, iteratee) => () => {
let item = collection()
item = item !== null ? iteratee(item) : item
return item
}
/**
* No Array's, Objects, Strings or methods used :)
*/
const numbers = reverse(map(range(1, 10), n => n ** 2))
forEach(numbers, console.log.bind(console))
/* ------------------------------------------------------------------------------ *\
* Old String Solution
\* ------------------------------------------------------------------------------ */
/** Get string length */
const strLen = (s) => {
let length = -1
while (s[++length]) {}
return length
}
/**
* @param {number} min
* @param {number} max
* @returns {string}
*
* @example
* range(1, 5) // -> "1,2,3,4,5,"
*/
const range = (min, max) => (min < max)
? `${min},${range(++min, max)}`
: `${max},`
const forEach = (collection, iteratee) => {
let num = ''
for (let i = 0; i < strLen(collection); i += 1) {
if (collection[i] === ',') {
iteratee(parseInt(num))
}
else num += range[i]
}
}
const map = (collection, iteratee) => {
let newCollection = ''
forEach(collection, num => newCollection += `${iteratee(num)},`)
return newCollection
}
const reverse = (collection) => {
let newCollection = ''
forEach(collection, num => newCollection = `${num},${newCollection}`)
return newCollection
}
/**
* Meets all restrictions apart from [] characters for strings :(
*/
const numbers = reverse(map(range(1, 10), n => n ** 2))
forEach(numbers, console.log.bind(console))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment