A list of small & fun functional programming exercises in JavaScript.
Please see CONTRIBUTING.
- Run
npm install
to install the dependencies (need node.js for npm). - Change
filename
intest/tests.js
to the name of your solution file (optional). - Make sure your solution file is in the
Solutions
folder. - Make sure your function names match the ones listed below as you're coding them.
- At the bottom of your solution file, add
module.exports = {
identity,
addb,
subb,
mulb,
minb,
maxb,
add,
sub,
mul,
min,
max,
addRecurse,
mulRecurse,
minRecurse,
maxRecurse,
not,
acc,
accPartial,
accRecurse,
fill,
fillRecurse,
set,
identityf,
addf,
liftf,
pure,
curryb,
curry,
inc,
twiceUnary,
doubl,
square,
twice,
reverseb,
reverse,
composeuTwo,
composeu,
composeb,
composeTwo,
compose,
limitb,
limit,
genFrom,
genTo,
genFromTo,
elementGen,
element,
collect,
filter,
filterTail,
concatTwo,
concat,
concatTail,
gensymf,
gensymff,
fibonaccif,
counter,
revocableb,
revocable,
extract,
m,
addmTwo,
addm,
liftmbM,
liftmb,
liftm,
exp,
expn,
addg,
liftg,
arrayg,
continuizeu,
continuize,
vector,
exploitVector,
vectorSafe,
pubsub,
mapRecurse,
filterRecurse,
};
- You can comment out any function names in the
module.exports
that you haven't written yet, but a lot of the tests depend on previous functions to run properly so it's safer to write the functions in order. - Finally,
npm run test
to run the tests.
- identity(x) ⇒
any
Write a function
identity
that takes an argument and returns that argument- addb(a, b) ⇒
number
Write a binary function
addb
that takes two numbers and returns their sum- subb(a, b) ⇒
number
Write a binary function
subb
that takes two numbers and returns their difference- mulb(a, b) ⇒
number
Write a binary function
mulb
that takes two numbers and returns their product- minb(a, b) ⇒
number
Write a binary function
minb
that takes two numbers and returns the smaller one- maxb(a, b) ⇒
number
Write a binary function
maxb
that takes two numbers and returns the larger one- add(...nums) ⇒
number
Write a function
add
that is generalized for any amount of arguments- sub(...nums) ⇒
number
Write a function
sub
that is generalized for any amount of arguments- mul(...nums) ⇒
number
Write a function
mul
that is generalized for any amount of arguments- min(...nums) ⇒
number
Write a function
min
that is generalized for any amount of arguments- max(...nums) ⇒
number
Write a function
max
that is generalized for any amount of arguments- addRecurse(...nums) ⇒
number
Write a function
addRecurse
that is the generalizedadd
function but uses recursion- mulRecurse(...nums) ⇒
number
Write a function
mulRecurse
that is the generalizedmul
function but uses recursion- minRecurse(...nums) ⇒
number
Write a function
minRecurse
that is the generalizedmin
function but uses recursion- maxRecurse(...nums) ⇒
number
Write a function
maxRecurse
that is the generalizedmax
function but uses recursion- not(func) ⇒
function
Write a function
not
that takes a function and returns the negation of its result- acc(func, initial) ⇒
function
Write a function
acc
that takes a function and an initial value and returns a function that runs the initial function on each argument, accumulating the result- accPartial(func, start, end) ⇒
function
Write a function
accPartial
that takes in a function, a start index, and an end index, and returns a function that accumulates a subset of its arguments by applying the given function to all elements between start and end.- accRecurse(func, initial) ⇒
function
Write a function
accRecurse
that does whatacc
does but uses recursion- fill(num) ⇒
array
Write a function
fill
that takes a number and returns an array with that many numbers equal to the given number- fillRecurse(num) ⇒
array
Write a function
fillRecurse
that does whatfill
does but uses recursion- set(...args) ⇒
array
Write a function
set
that is given a list of arguments and returns an array with all duplicates removed- identityf(x) ⇒
function
Write a function
identityf
that takes an argument and returns a function that returns that argument- addf(a) ⇒
function
Write a function
addf
that adds from two invocations- liftf(binary) ⇒
function
Write a function
liftf
that takes a binary function, and makes it callable with two invocations- pure(x, y) ⇒
array
Write a pure function
pure
that is a wrapper arround the impure functionimpure
function impure(x) { y++; z = x * y; } var y = 5, z; impure(20); z; // 120 impure(25); z; // 175
- curryb(binary, a) ⇒
function
Write a function
curryb
that takes a binary function and an argument, and returns a function that can take a second argument- curry(func, ...outer) ⇒
function
Write a function
curry
that is generalized for any amount of arguments- inc(x) ⇒
number
Without writting any new functions, show multiple ways to create the
inc
function- twiceUnary(binary) ⇒
function
Write a function
twiceUnary
that takes a binary function and returns a unary function that passes its argument to the binary function twice- doubl(x) ⇒
number
Use the function
twiceUnary
to create thedoubl
function- square(x) ⇒
number
Use the function
twiceUnary
to create thesquare
function- twice(x) ⇒
any
Write a function
twice
that is generalized for any amount of arguments- reverseb(binary) ⇒
function
Write a function
reverseb
that reverses the arguments of a binary function- reverse(func) ⇒
function
Write a function
reverse
that is generalized for any amount of arguments- composeuTwo(unary1, unary2) ⇒
function
Write a function
composeuTwo
that takes two unary functions and returns a unary function that calls them both- composeu(...funcs) ⇒
any
Write a function
composeu
that is generalized for any amount of arguments- composeb(binary1, binary2) ⇒
function
Write a function
composeb
that takes two binary functions and returns a function that calls them both- composeTwo(func1, func2) ⇒
function
Write a function
composeTwo
that takes two functions and returns a function that calls them both- compose(...funcs) ⇒
function
Write a function
compose
that takes any amount of functions and returns a function that takes any amount of arguments and gives them to the first function, then that result to the second function and so on- limitb(binary, lmt) ⇒
function
Write a function
limitb
that allows a binary function to be called a limited number of times- limit(func, lmt) ⇒
function
Write a function
limit
that is generalized for any amount of arguments- genFrom(x) ⇒
function
Write a function
genFrom
that produces a generator that will produces a series of values- genTo(gen, lmt) ⇒
function
Write a function
genTo
that takes a generator and an end limit, and returns a generator that will produce numbers up to that limit- genFromTo(start, end) ⇒
function
Write a function
genFromTo
that produces a generator that will produce values in a range- elementGen(array, gen) ⇒
function
Write a function
elementGen
that takes an array and a generator and returns a generator that will produce elements from the array- element(array, gen) ⇒
function
Write a function
element
that is a modifiedelementGen
function so that the generator argument is optional. If a generator is not provided, then each of the elements of the array will be produced.- collect(gen, array) ⇒
function
Write a function
collect
that takes a generator and an array and produces a function that will collect the results in the array- filter(gen, predicate) ⇒
function
Write a function
filter
that takes a generator and a predicate and produces a generator that produces only the values approved by the predicate- filterTail(gen, predicate) ⇒
function
Write a function
filterTail
that uses tail-recursion to perform the filtering- concatTwo(gen1, gen2) ⇒
function
Write a function
concatTwo
that takes two generators and produces a generator that combines the sequences- concat(...gens) ⇒
function
Write a function
concat
that is generalized for any amount of arguments- concatTail(...gens) ⇒
function
Write a function
concatTail
that uses tail-recursion to perform the concating- gensymf(symbol) ⇒
function
Write a function
gensymf
that makes a function that generates unique symbols- gensymff(unary, seed) ⇒
function
Write a function
gensymff
that takes a unary function and a seed and returns agensymf
- fibonaccif(first, second) ⇒
function
Write a function
fibonaccif
that returns a generator that will return the next fibonacci number- counter(i) ⇒
object
Write a function
counter
that returns an object containing two functions that implement an up/down counter, hiding the counter- revocableb(binary) ⇒
object
Write a function
revocableb
that takes a binary function, and returns an object containing aninvoke
function that can invoke a function and arevoke
function that disables theinvoke
function- revocable(func) ⇒
object
Write a function
revocable
that is generalized for any amount of arguments- extract(array, prop) ⇒
array
Write a function
extract
that takes an array of objects and an object property name and converts each object in the array by extracting that property- m(value, source) ⇒
object
Write a function
m
that takes a value and an optional source string and returns them in an object- addmTwo(m1, m2) ⇒
object
Write a function
addmTwo
that adds twom
objects and returns anm
object- addm(...ms) ⇒
object
Write a function
addm
that is generalized for any amount of arguments- liftmbM(binary, op) ⇒
object
Write a function
liftmbM
that takes a binary function and a string and returns a function that acts onm
objects- liftmb(binary, op) ⇒
object
Write a function
liftmb
that is a modified functionliftmbM
that can accept arguments that are either numbers or m objects- liftm(func, op) ⇒
object
Write a function
liftm
that is generalized for any amount of arguments- exp(value) ⇒
any
Write a function
exp
that evaluates simple array expressions- expn(value) ⇒
any
Write a function
expn
that is a modifiedexp
that can evaluate nested array expressions- addg(value) ⇒
number
|undefined
Write a function
addg
that adds from many invocations, until it sees an empty invocation- liftg(binary) ⇒
function
Write a function
liftg
that will take a binary function and apply it to many invocations- arrayg(value) ⇒
array
Write a function
arrayg
that will build an array from many invocations- continuizeu(unary) ⇒
function
Write a function
continuizeu
that takes a unary function and returns a function that takes a callback and an argument- continuize(func) ⇒
function
Write a function
continuize
that takes a function and returns a function that takes a callback and arguments- vector()
Make an array wrapper object with methods
get
,store
, andappend
, such that an attacker cannot get access to the private array- exploitVector()
Let's assume your
vector
implementation looks like something like this:let vector = () => { let array = [] return { append: (v) => array.push(v), get: (i) => array[i], store: (i, v) => array[i] = v } }
Can you spot any security concerns with this approach? Mainly, can we get access to the
array
outside ofvector
? Note: the issue has nothing to do with prototypes and we can assume that global prototypes cannot be altered. Hint: Think about usingthis
in a method invocation. Can we override a method ofvector
?- vectorSafe()
How would you rewrite
vector
to deal with the issue from above?- pubsub()
Make a function
pubsub
that makes a publish/subscribe object. It will reliably deliver all publications to all subscribers in the right order.- mapRecurse(array, callback) ⇒
array
Make a function
mapRecurse
that performs a transformation for each element of a given array, recursively- filterRecurse(array, predicate) ⇒
array
Make a function
filterRecurse
that takes in an array and a predicate function and returns a new array by filtering out all items using the predicate, recursively.
Write a function identity
that
takes an argument and returns
that argument
Param | Type |
---|---|
x | any |
Example
identity(3) // 3
Write a binary function addb
that takes two numbers and returns
their sum
Param | Type |
---|---|
a | number |
b | number |
Example
addb(3, 4) // 3 + 4 = 7
Write a binary function subb
that takes two numbers and returns
their difference
Param | Type |
---|---|
a | number |
b | number |
Example
subb(3, 4) // 3 - 4 = -1
Write a binary function mulb
that takes two numbers and returns
their product
Param | Type |
---|---|
a | number |
b | number |
Example
mulb(3, 4) // 3 * 4 = 12
Write a binary function minb
that takes two numbers and returns
the smaller one
Param | Type |
---|---|
a | number |
b | number |
Example
minb(3, 4) // 3
Write a binary function maxb
that takes two numbers and returns
the larger one
Param | Type |
---|---|
a | number |
b | number |
Example
maxb(3, 4) // 4
Write a function add
that
is generalized for any
amount of arguments
Param | Type |
---|---|
...nums | number |
Example
add(1, 2, 4) // 1 + 2 + 4 = 7
Write a function sub
that
is generalized for any
amount of arguments
Param | Type |
---|---|
...nums | number |
Example
sub(1, 2, 4) // 1 - 2 - 4 = -5
Write a function mul
that
is generalized for any
amount of arguments
Param | Type |
---|---|
...nums | number |
Example
mul(1, 2, 4) // 1 * 2 * 4 = 8
Write a function min
that
is generalized for any
amount of arguments
Param | Type |
---|---|
...nums | number |
Example
min(1, 2, 4) // 1
Write a function max
that
is generalized for any
amount of arguments
Param | Type |
---|---|
...nums | number |
Example
max(1, 2, 4) // 4
Write a function addRecurse
that
is the generalized add
function
but uses recursion
Param | Type |
---|---|
...nums | number |
Example
addRecurse(1, 2, 4) // 1 + 2 + 4 = 7
Write a function mulRecurse
that
is the generalized mul
function
but uses recursion
Param | Type |
---|---|
...nums | number |
Example
mulRecurse(1, 2, 4) // 1 * 2 * 4 = 8
Write a function minRecurse
that
is the generalized min
function
but uses recursion
Param | Type |
---|---|
...nums | number |
Example
minRecurse(1, 2, 4) // 1
Write a function maxRecurse
that
is the generalized max
function
but uses recursion
Param | Type |
---|---|
...nums | number |
Example
maxRecurse(1, 2, 4) // 4
Write a function not
that
takes a function and returns
the negation of its result
Param | Type |
---|---|
func | function |
Example
const isOdd = (x) => x % 2 === 1
const isEven = not(isOdd)
isEven(1) // false
isEven(2) // true
Write a function acc
that
takes a function and an
initial value and returns
a function that runs the
initial function on each
argument, accumulating the
result
Param | Type |
---|---|
func | function |
initial | any |
Example
let add = acc(addb, 0)
add(1, 2, 4) // 7
let mul = acc(mulb, 1)
mul(1, 2, 4) // 8
Write a function accPartial
that
takes in a function, a start index,
and an end index, and returns a
function that accumulates a subset
of its arguments by applying the
given function to all elements
between start and end.
Param | Type |
---|---|
func | function |
start | number |
end | number |
Example
const addSecondToThird = accPartial(add, 1, 3)
addSecondToThird(1, 2, 4, 8) // [ 1, 6, 8 ]
Write a function accRecurse
that
does what acc
does but uses recursion
Param | Type |
---|---|
func | function |
initial | number |
Example
let add = accRecurse(addb, 0)
add(1, 2, 4) // 7
let mul = accRecurse(mulb, 1)
mul(1, 2, 4) // 8
Write a function fill
that
takes a number and returns
an array with that many
numbers equal to the given
number
Param | Type |
---|---|
num | number |
Example
fill(3) // [ 3, 3, 3 ]
Write a function fillRecurse
that
does what fill
does but uses recursion
Param | Type |
---|---|
num | number |
Example
fillRecurse(3) // [ 3, 3, 3 ]
Write a function set
that
is given a list of arguments
and returns an array with
all duplicates removed
Param | Type |
---|---|
...args | any |
Example
let oneAndTwo = set(1, 1, 1, 2, 2, 2) // [ 1, 2 ]
Write a function identityf
that takes an argument and
returns a function that
returns that argument
Param | Type |
---|---|
x | any |
Example
let three = identityf(3)
three() // 3
Write a function addf
that
adds from two invocations
Param | Type |
---|---|
a | number |
Example
addf(3)(4) // 7
Write a function liftf
that
takes a binary function, and
makes it callable with two
invocations
Param | Type |
---|---|
binary | function |
Example
let addf = liftf(addb)
addf(3)(4) // 7
liftf(mulb)(5)(6) // 30
Write a pure function pure
that
is a wrapper arround the impure
function impure
function impure(x) {
y++;
z = x * y;
}
var y = 5, z;
impure(20);
z; // 120
impure(25);
z; // 175
Returns: array
- an array containing y
and z
Param | Type |
---|---|
x | number |
y | number |
Example
pure(20, 5) // [ 6, 120 ]
pure(25, 6) // [ 7, 175 ]
Write a function curryb
that
takes a binary function and
an argument, and returns a
function that can take a
second argument
Param | Type |
---|---|
binary | function |
a | any |
Example
let add3 = curryb(addb, 3)
add3(4) // 7
curryb(mulb, 5)(6) // 30
Write a function curry
that
is generalized for any amount
of arguments
Param | Type |
---|---|
func | function |
...outer | any |
Example
curry(add, 1, 2, 4)(4, 2, 1) = 1 + 2 + 4 + 4 + 2 + 1 = 14
curry(sub, 1, 2, 4)(4, 2, 1) = 1 - 2 - 4 - 4 - 2 - 1 = -12
curry(mul, 1, 2, 4)(4, 2, 1) = 1 * 2 * 4 * 4 * 2 * 1 = 64
Without writting any new functions,
show multiple ways to create the inc
function
Param | Type |
---|---|
x | number |
Example
inc(5) // 6
inc(inc(5)) // 7
Write a function twiceUnary
that takes a binary function
and returns a unary function
that passes its argument to
the binary function twice
Param | Type |
---|---|
binary | function |
Example
let doubl = twiceUnary(addb)
doubl(11) // 22
let square = twiceUnary(mulb)
square(11) // 121
Use the function twiceUnary
to
create the doubl
function
Param | Type |
---|---|
x | number |
Example
doubl(11) // 22
Use the function twiceUnary
to
create the square
function
Param | Type |
---|---|
x | number |
Example
square(11) // 121
Write a function twice
that
is generalized for any amount
of arguments
Param | Type |
---|---|
x | function |
Example
let doubleSum = twice(add)
doubleSum(1, 2, 4) // 1 + 2 + 4 + 1 + 2 + 4 = 14
Write a function reverseb
that
reverses the arguments of a
binary function
Param | Type |
---|---|
binary | function |
Example
let bus = reverseb(subb)
bus(3, 2) // -1
Write a function reverse
that
is generalized for any amount
of arguments
Param | Type |
---|---|
func | function |
Example
reverse(sub)(1, 2, 4) // 4 - 2 - 1 = 1
Write a function composeuTwo
that
takes two unary functions and
returns a unary function that
calls them both
Param | Type |
---|---|
unary1 | function |
unary2 | function |
Example
composeuTwo(doubl, square)(5) // (5 * 2)^2 = 100
Write a function composeu
that
is generalized for any amount
of arguments
Param | Type |
---|---|
...funcs | function |
Example
composeu(doubl, square, identity, curry(add, 1, 2))(5) // (5 * 2)^2 + 1 + 2 = 103
Write a function composeb
that
takes two binary functions and
returns a function that calls
them both
Param | Type |
---|---|
binary1 | function |
binary2 | function |
Example
composeb(addb, mulb)(2, 3, 7) // (2 + 3) * 7 = 35
Write a function composeTwo
that
takes two functions and returns a
function that calls them both
Param | Type |
---|---|
func1 | function |
func2 | function |
Example
composeTwo(add, square)(2, 3, 7, 5) // (2 + 3 + 7 + 5)^2 = 289
Write a function compose
that
takes any amount of functions
and returns a function that takes
any amount of arguments and gives
them to the first function, then
that result to the second function
and so on
Param | Type |
---|---|
...funcs | function |
Example
const f = compose(add, doubl, fill, max)
f(0, 1, 2)
// add(0, 1, 2) -> 3
// doubl(3) -> 6
// fill(6) -> [ 6, 6, 6, 6, 6, 6 ]
// max(6, 6, 6, 6, 6, 6) -> 6
Write a function limitb
that allows a binary function
to be called a limited number
of times
Param | Type |
---|---|
binary | function |
lmt | number |
Example
let addLmtb = limitb(addb, 1)
addLmtb(3, 4) // 7
addLmtb(3, 5) // undefined
Write a function limit
that
is generalized for any amount
of arguments
Param | Type |
---|---|
func | function |
lmt | number |
Example
let addLmt = limit(add, 1)
addLmt(1, 2, 4) // 7
addLmt(3, 5, 9, 2) // undefined
Write a function genFrom
that
produces a generator that will
produces a series of values. Follows the iterator protocol for the returned format.
Param | Type |
---|---|
x | number |
Example
let index = genFrom(0)
index.next().value // 0
index.next().value // 1
index.next().value // 2
Write a function genTo
that
takes a generator and an end
limit, and returns a generator
that will produce numbers up
to that limit
Param | Type |
---|---|
gen | function |
lmt | number |
Example
let index = genTo(genFrom(1), 3)
index.next().value // 1
index.next().value // 2
index.next().value // undefined
Write a function genFromTo
that
produces a generator that will
produce values in a range
Param | Type |
---|---|
start | number |
end | number |
Example
let index = genFromTo(0, 3)
index.next().value // 0
index.next().value // 1
index.next().value // 2
index.next().value // undefined
Write a function elementGen
that
takes an array and a generator
and returns a generator that will
produce elements from the array
Param | Type |
---|---|
array | array |
gen | function |
Example
let ele = elementGen(['a', 'b', 'c', 'd'], genFromTo(1, 3))
ele.next().value // 'b'
ele.next().value // 'c'
ele.next().value // undefined
Write a function element
that is a
modified elementGen
function so that
the generator argument is optional.
If a generator is not provided, then
each of the elements of the array
will be produced.
Param | Type |
---|---|
array | array |
gen | function |
Example
let ele = element(['a', 'b', 'c', 'd'])
ele.next().value // 'a'
ele.next().value // 'b'
ele.next().value // 'c'
ele.next().value // 'd'
ele.next().value // undefined
Write a function collect
that takes a
generator and an array and produces
a function that will collect the results
in the array
Param | Type |
---|---|
gen | function |
array | array |
Example
let array = []
let col = collect(genFromTo(0, 2), array)
col.next().value // 0
col.next().value // 1
col.next().value // undefined
array // [0, 1]
Write a function filter
that takes a
generator and a predicate and produces
a generator that produces only the
values approved by the predicate
Param | Type |
---|---|
gen | function |
predicate | function |
Example
let third = (val) => val % 3 === 0
let fil = filter(genFromTo(0, 5), third)
fil.next().value // 0
fil.next().value // 3
fil.next().value // undefined
Write a function filterTail
that uses
tail-recursion to perform the filtering
Param | Type |
---|---|
gen | function |
predicate | function |
Example
let third = (val) => val % 3 === 0
let fil = filterTail(genFromTo(0, 5), third)
fil.next().value // 0
fil.next().value // 3
fil.next().value // undefined
Write a function concatTwo
that takes
two generators and produces a generator
that combines the sequences
Param | Type |
---|---|
gen1 | function |
gen2 | function |
Example
let con = concatTwo(genFromTo(0, 3), genFromTo(0, 2))
con.next().value // 0
con.next().value // 1
con.next().value // 2
con.next().value // 0
con.next().value // 1
con.next().value // undefined
Write a function concat
that
is generalized for any amount
of arguments
Param | Type |
---|---|
...gens | function |
Example
let con = concat(genFromTo(0, 3), genFromTo(0, 2), genFromTo(5, 7))
con.next().value // 0
con.next().value // 1
con.next().value // 2
con.next().value // 0
con.next().value // 1
con.next().value // 5
con.next().value // 6
con.next().value // undefined
Write a function concatTail
that uses
tail-recursion to perform the concating
Param | Type |
---|---|
...gens | function |
Example
let con = concatTail(genFromTo(0, 3), genFromTo(0, 2), genFromTo(5, 7))
con.next().value // 0
con.next().value // 1
con.next().value // 2
con.next().value // 0
con.next().value // 1
con.next().value // 5
con.next().value // 6
con.next().value // undefined
Write a function gensymf
that
makes a function that generates
unique symbols
Param | Type |
---|---|
symbol | string |
Example
let genG = gensymf('G')
let genH = gensymf('H')
genG.next().value // 'G1'
genH.next().value // 'H1'
genG.next().value // 'G2'
genH.next().value // 'H2'
Write a function gensymff
that
takes a unary function and a
seed and returns a gensymf
Param | Type |
---|---|
unary | function |
seed | number |
Example
let gensymf = gensymff(inc, 0)
let genG = gensymf('G')
let genH = gensymf('H')
genG.next().value // 'G1'
genH.next().value // 'H1'
genG.next().value // 'G2'
genH.next().value // 'H2'
Write a function fibonaccif
that
returns a generator that will
return the next fibonacci number
Param | Type |
---|---|
first | number |
second | number |
Example
let fib = fibonaccif(0, 1)
fib.next().value // 0
fib.next().value // 1
fib.next().value // 1
fib.next().value // 2
fib.next().value // 3
fib.next().value // 5
fib.next().value // 8
Write a function counter
that
returns an object containing
two functions that implement
an up/down counter, hiding
the counter
Param | Type |
---|---|
i | number |
Example
let obj = counter(10)
let { up, down } = obj
up() // 11
down() // 10
down() // 9
up() // 10
Write a function revocableb
that takes a binary function, and
returns an object containing an
invoke
function that can invoke a
function and a revoke
function
that disables the invoke
function
Param | Type |
---|---|
binary | function |
Example
let rev = revocableb(addb)
rev.invoke(3, 4) // 7
rev.revoke()
rev.invoke(5, 7) // undefined
Write a function revocable
that
is generalized for any amount of
arguments
Param | Type |
---|---|
func | function |
Example
let rev = revocable(add)
rev.invoke(3, 4) // 7
rev.revoke()
rev.invoke(5, 7) // undefined
Write a function extract
that
takes an array of objects and an
object property name and converts
each object in the array by
extracting that property
Param | Type |
---|---|
array | array |
prop | string |
Example
let people = [{ name: 'john' }, { name: 'bob' }]
let names = extract(people, 'name') // ['john', 'bob']
Write a function m
that
takes a value and an
optional source string
and returns them in an
object
Param | Type |
---|---|
value | any |
source | any |
Example
m(1) // {value:1, source:"1"}
m(Math.PI, 'pi') // {value:3.14159..., source:"pi"}
Write a function addmTwo
that
adds two m
objects and
returns an m
object
Param | Type |
---|---|
m1 | function |
m2 | function |
Example
addmTwo(m(3), m(4)) // {value:7, source:"(3+4)"}
addmTwo(m(1, m(Math.PI, 'pi'))) // {value:4.14159..., source:"(1+pi)"}
Write a function addm
that
is generalized for any amount of
arguments
Param | Type |
---|---|
...ms | function |
Example
addm(m(1), m(2), m(4)) // {value:7, source:"(1+2+4)"}
Write a function liftmbM
that
takes a binary function and
a string and returns a function
that acts on m
objects
Param | Type |
---|---|
binary | function |
op | string |
Example
let addmb = liftmbM(addb, '+')
addmb(m(3), m(4)) // {value:7, source:"(3+4)"}
liftmbM(mul, '*')(m(3), m(4)) // {value:12, source:"(3*4)"}
Write a function liftmb
that
is a modified function liftmbM
that can accept arguments that
are either numbers or m objects
Param | Type |
---|---|
binary | function |
op | string |
Example
let addmb = liftmb(addb, '+')
addmb(3, 4) // {value:7, source:"(3+4)"}
Write a function liftm
that
is generalized for any amount of
arguments
Param | Type |
---|---|
func | function |
op | string |
Example
let addm = liftm(add, '+')
addm(m(3), m(4)) // {value:7, source:"(3+4)"}
liftm(mul, '*')(m(3), m(4)) // {value:12, source:"(3*4)"}
Write a function exp
that
evaluates simple array
expressions
Param | Type |
---|---|
value | any |
Example
let sae = [mul, 1, 2, 4]
exp(sae) // 1 * 2 * 4 = 8
exp(42) // 42
Write a function expn
that is a modified exp
that
can evaluate nested array
expressions
Param | Type |
---|---|
value | any |
Example
let nae = [Math.sqrt, [add, [square, 3], [square, 4]]]
expn(nae) // sqrt(((3*3)+(4*4))) === 5
Write a function addg
that
adds from many invocations,
until it sees an empty
invocation
Param | Type |
---|---|
value | number |
Example
addg() // undefined
addg(2)() // 2
addg(2)(7)() // 9
addg(3)(0)(4)() // 7
addg(1)(2)(4)(8)() // 15
Write a function liftg
that
will take a binary function
and apply it to many invocations
Param | Type |
---|---|
binary | function |
Example
liftg(mulb)() // undefined
liftg(mulb)(3)() // 3
liftg(mulb)(3)(0)(4)() // 0
liftg(mulb)(1)(2)(4)(8)() // 64
Write a function arrayg
that
will build an array from many
invocations
Param | Type |
---|---|
value | any |
Example
arrayg() // []
arrayg(3)() // [3]
arrayg(3)(4)(5)() // [3, 4, 5]
Write a function continuizeu
that takes a unary function
and returns a function that
takes a callback and an
argument
Param | Type |
---|---|
unary | function |
Example
let sqrtc = continuizeu(Math.sqrt)
sqrtc(console.log, 81) // logs '9'
Write a function continuize
that takes a function and
returns a function that
takes a callback and arguments
Param | Type |
---|---|
func | function |
Example
let mullc = continuize(mul)
mullc(console.log, 81, 4, 2) // logs '648'
Make an array wrapper object
with methods get
, store
,
and append
, such that an
attacker cannot get access
to the private array
Example
let v = vector()
v.append(7)
v.store(1, 8)
v.get(0) // 7
v.get(1) // 8
Let's assume your vector
implementation looks like
something like this:
let vector = () => {
let array = []
return {
append: (v) => array.push(v),
get: (i) => array[i],
store: (i, v) => array[i] = v
}
}
Can you spot any security concerns with
this approach? Mainly, can we get access
to the array
outside of vector
?
Note*: the issue has nothing to do with
prototypes and we can assume that global
prototypes cannot be altered.
Hint*: Think about using this
in a
method invocation. Can we override a
method of vector
?
Example
let v = vector()
v.append(1)
v.append(2)
let internalData = exploitVector(v) // [1, 2]
How would you rewrite vector
to deal
with the issue from above?
Example
let v = vectorSafe()
v.append(1)
v.append(2)
let internalData = exploitVector(v) // undefined
Make a function pubsub
that
makes a publish/subscribe object.
It will reliably deliver all
publications to all subscribers
in the right order.
Example
let ps = pubsub()
ps.subscribe(console.log)
ps.publish('It works!') // logs 'It works!'
Make a function mapRecurse
that
performs a transformation for each
element of a given array, recursively
Param | Type |
---|---|
array | array |
callback | function |
Example
mapRecurse([1, 2, 3, 4], (x) => x * 2) // [ 2, 4, 6, 8 ]
Make a function filterRecurse
that
takes in an array and a predicate
function and returns a new array by
filtering out all items using the
predicate, recursively.
Param | Type |
---|---|
array | array |
predicate | function |
Example
filterRecurse([1, 2, 3, 4], (x) => x % 2 === 0) // [ 2, 4 ]