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). If you don't have node please visit the Node JS website to download. It is recommended to download the LTS version. - 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, copy and paste the following code:
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 ]