https://github.com/zero-to-mastery/js_fun_practice
A list of small & fun functional programming exercises in JavaScript
https://github.com/zero-to-mastery/js_fun_practice
hacktoberfest javascript-practice-problems javascript-puzzles
Last synced: 6 months ago
JSON representation
A list of small & fun functional programming exercises in JavaScript
- Host: GitHub
- URL: https://github.com/zero-to-mastery/js_fun_practice
- Owner: zero-to-mastery
- License: mit
- Created: 2018-05-20T21:31:52.000Z (over 7 years ago)
- Default Branch: master
- Last Pushed: 2024-01-10T22:50:31.000Z (almost 2 years ago)
- Last Synced: 2024-01-10T23:55:53.297Z (almost 2 years ago)
- Topics: hacktoberfest, javascript-practice-problems, javascript-puzzles
- Language: JavaScript
- Homepage:
- Size: 538 KB
- Stars: 674
- Watchers: 18
- Forks: 545
- Open Issues: 22
-
Metadata Files:
- Readme: README.md
- Contributing: CONTRIBUTING.md
- License: LICENSE
Awesome Lists containing this project
README
# js-function-fun
A list of small & fun functional programming exercises in JavaScript.
## Contributing
Please see [CONTRIBUTING](CONTRIBUTING.md).
## Testing
### To test the functions:
1. Run npm install to install the dependencies (need node.js for npm). If you don't have node please visit the [Node JS](https://nodejs.org/en/) website to download. It is recommended to download the LTS version.
2. Change filename in test/tests.js to the name of your solution file (optional).
3. Make sure your solution file is in the Solutions folder.
4. Make sure your function names match the ones listed below as you're coding them.
5. At the bottom of your solution file, copy and paste the following code:
```js
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,
};
```
6. 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.
7. Finally, npm run test to run the tests.
## Functions
-
identity(x) ⇒any -
Write a function
identitythat
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
addthat
is generalized for any
amount of arguments -
sub(...nums) ⇒number -
Write a function
subthat
is generalized for any
amount of arguments -
mul(...nums) ⇒number -
Write a function
multhat
is generalized for any
amount of arguments -
min(...nums) ⇒number -
Write a function
minthat
is generalized for any
amount of arguments -
max(...nums) ⇒number -
Write a function
maxthat
is generalized for any
amount of arguments -
addRecurse(...nums) ⇒number -
Write a function
addRecursethat
is the generalizedaddfunction
but uses recursion -
mulRecurse(...nums) ⇒number -
Write a function
mulRecursethat
is the generalizedmulfunction
but uses recursion -
minRecurse(...nums) ⇒number -
Write a function
minRecursethat
is the generalizedminfunction
but uses recursion -
maxRecurse(...nums) ⇒number -
Write a function
maxRecursethat
is the generalizedmaxfunction
but uses recursion -
not(func) ⇒function -
Write a function
notthat
takes a function and returns
the negation of its result -
acc(func, initial) ⇒function -
Write a function
accthat
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
accPartialthat
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
accRecursethat
does whataccdoes but uses recursion -
fill(num) ⇒array -
Write a function
fillthat
takes a number and returns
an array with that many
numbers equal to the given
number -
fillRecurse(num) ⇒array -
Write a function
fillRecursethat
does whatfilldoes but uses recursion -
set(...args) ⇒array -
Write a function
setthat
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
addfthat
adds from two invocations -
liftf(binary) ⇒function -
Write a function
liftfthat
takes a binary function, and
makes it callable with two
invocations -
pure(x, y) ⇒array -
Write a pure function
purethat
is a wrapper arround the impure
functionimpure```js
function impure(x) {
y++;
z = x * y;
}var y = 5, z;
impure(20);
z; // 120impure(25);
z; // 175
``` -
curryb(binary, a) ⇒function -
Write a function
currybthat
takes a binary function and
an argument, and returns a
function that can take a
second argument -
curry(func, ...outer) ⇒function -
Write a function
currythat
is generalized for any amount
of arguments -
inc(x) ⇒number -
Without writting any new functions,
show multiple ways to create theinc
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
twiceUnaryto
create thedoublfunction -
square(x) ⇒number -
Use the function
twiceUnaryto
create thesquarefunction -
twice(x) ⇒any -
Write a function
twicethat
is generalized for any amount
of arguments -
reverseb(binary) ⇒function -
Write a function
reversebthat
reverses the arguments of a
binary function -
reverse(func) ⇒function -
Write a function
reversethat
is generalized for any amount
of arguments -
composeuTwo(unary1, unary2) ⇒function -
Write a function
composeuTwothat
takes two unary functions and
returns a unary function that
calls them both -
composeu(...funcs) ⇒any -
Write a function
composeuthat
is generalized for any amount
of arguments -
composeb(binary1, binary2) ⇒function -
Write a function
composebthat
takes two binary functions and
returns a function that calls
them both -
composeTwo(func1, func2) ⇒function -
Write a function
composeTwothat
takes two functions and returns a
function that calls them both -
compose(...funcs) ⇒function -
Write a function
composethat
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
limitthat
is generalized for any amount
of arguments -
genFrom(x) ⇒function -
Write a function
genFromthat
produces a generator that will
produces a series of values -
genTo(gen, lmt) ⇒function -
Write a function
genTothat
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
genFromTothat
produces a generator that will
produce values in a range -
elementGen(array, gen) ⇒function -
Write a function
elementGenthat
takes an array and a generator
and returns a generator that will
produce elements from the array -
element(array, gen) ⇒function -
Write a function
elementthat is a
modifiedelementGenfunction 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
collectthat 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
filterthat 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
filterTailthat uses
tail-recursion to perform the filtering -
concatTwo(gen1, gen2) ⇒function -
Write a function
concatTwothat takes
two generators and produces a generator
that combines the sequences -
concat(...gens) ⇒function -
Write a function
concatthat
is generalized for any amount
of arguments -
concatTail(...gens) ⇒function -
Write a function
concatTailthat uses
tail-recursion to perform the concating -
gensymf(symbol) ⇒function -
Write a function
gensymfthat
makes a function that generates
unique symbols -
gensymff(unary, seed) ⇒function -
Write a function
gensymffthat
takes a unary function and a
seed and returns agensymf -
fibonaccif(first, second) ⇒function -
Write a function
fibonaccifthat
returns a generator that will
return the next fibonacci number -
counter(i) ⇒object -
Write a function
counterthat
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 aninvokefunction that can invoke a
function and arevokefunction
that disables theinvokefunction -
revocable(func) ⇒object -
Write a function
revocablethat
is generalized for any amount of
arguments -
extract(array, prop) ⇒array -
Write a function
extractthat
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
mthat
takes a value and an
optional source string
and returns them in an
object -
addmTwo(m1, m2) ⇒object -
Write a function
addmTwothat
adds twomobjects and
returns anmobject -
addm(...ms) ⇒object -
Write a function
addmthat
is generalized for any amount of
arguments -
liftmbM(binary, op) ⇒object -
Write a function
liftmbMthat
takes a binary function and
a string and returns a function
that acts onmobjects -
liftmb(binary, op) ⇒object -
Write a function
liftmbthat
is a modified functionliftmbM
that can accept arguments that
are either numbers or m objects -
liftm(func, op) ⇒object -
Write a function
liftmthat
is generalized for any amount of
arguments -
exp(value) ⇒any -
Write a function
expthat
evaluates simple array
expressions -
expn(value) ⇒any -
Write a function
expn
that is a modifiedexpthat
can evaluate nested array
expressions -
addg(value) ⇒number|undefined -
Write a function
addgthat
adds from many invocations,
until it sees an empty
invocation -
liftg(binary) ⇒function -
Write a function
liftgthat
will take a binary function
and apply it to many invocations -
arrayg(value) ⇒array -
Write a function
arraygthat
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 methodsget,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:```js
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 thearrayoutside ofvector?
Note: the issue has nothing to do with
prototypes and we can assume that global
prototypes cannot be altered.
Hint: Think about usingthisin a
method invocation. Can we override a
method ofvector? - vectorSafe()
-
How would you rewrite
vectorto deal
with the issue from above? - pubsub()
-
Make a function
pubsubthat
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
mapRecursethat
performs a transformation for each
element of a given array, recursively -
filterRecurse(array, predicate) ⇒array -
Make a function
filterRecursethat
takes in an array and a predicate
function and returns a new array by
filtering out all items using the
predicate, recursively.
## identity(x) ⇒ any
Write a function `identity` that
takes an argument and returns
that argument
| Param | Type |
| ----- | ---------------- |
| x | any |
**Example**
```js
identity(3) // 3
```
## addb(a, b) ⇒ number
Write a binary function `addb`
that takes two numbers and returns
their sum
| Param | Type |
| ----- | ------------------- |
| a | number |
| b | number |
**Example**
```js
addb(3, 4) // 3 + 4 = 7
```
## subb(a, b) ⇒ number
Write a binary function `subb`
that takes two numbers and returns
their difference
| Param | Type |
| ----- | ------------------- |
| a | number |
| b | number |
**Example**
```js
subb(3, 4) // 3 - 4 = -1
```
## mulb(a, b) ⇒ number
Write a binary function `mulb`
that takes two numbers and returns
their product
| Param | Type |
| ----- | ------------------- |
| a | number |
| b | number |
**Example**
```js
mulb(3, 4) // 3 * 4 = 12
```
## minb(a, b) ⇒ number
Write a binary function `minb`
that takes two numbers and returns
the smaller one
| Param | Type |
| ----- | ------------------- |
| a | number |
| b | number |
**Example**
```js
minb(3, 4) // 3
```
## maxb(a, b) ⇒ number
Write a binary function `maxb`
that takes two numbers and returns
the larger one
| Param | Type |
| ----- | ------------------- |
| a | number |
| b | number |
**Example**
```js
maxb(3, 4) // 4
```
## add(...nums) ⇒ number
Write a function `add` that
is generalized for any
amount of arguments
| Param | Type |
| ------- | ------------------- |
| ...nums | number |
**Example**
```js
add(1, 2, 4) // 1 + 2 + 4 = 7
```
## sub(...nums) ⇒ number
Write a function `sub` that
is generalized for any
amount of arguments
| Param | Type |
| ------- | ------------------- |
| ...nums | number |
**Example**
```js
sub(1, 2, 4) // 1 - 2 - 4 = -5
```
## mul(...nums) ⇒ number
Write a function `mul` that
is generalized for any
amount of arguments
| Param | Type |
| ------- | ------------------- |
| ...nums | number |
**Example**
```js
mul(1, 2, 4) // 1 * 2 * 4 = 8
```
## min(...nums) ⇒ number
Write a function `min` that
is generalized for any
amount of arguments
| Param | Type |
| ------- | ------------------- |
| ...nums | number |
**Example**
```js
min(1, 2, 4) // 1
```
## max(...nums) ⇒ number
Write a function `max` that
is generalized for any
amount of arguments
| Param | Type |
| ------- | ------------------- |
| ...nums | number |
**Example**
```js
max(1, 2, 4) // 4
```
## addRecurse(...nums) ⇒ number
Write a function `addRecurse` that
is the generalized `add` function
but uses recursion
| Param | Type |
| ------- | ------------------- |
| ...nums | number |
**Example**
```js
addRecurse(1, 2, 4) // 1 + 2 + 4 = 7
```
## mulRecurse(...nums) ⇒ number
Write a function `mulRecurse` that
is the generalized `mul` function
but uses recursion
| Param | Type |
| ------- | ------------------- |
| ...nums | number |
**Example**
```js
mulRecurse(1, 2, 4) // 1 * 2 * 4 = 8
```
## minRecurse(...nums) ⇒ number
Write a function `minRecurse` that
is the generalized `min` function
but uses recursion
| Param | Type |
| ------- | ------------------- |
| ...nums | number |
**Example**
```js
minRecurse(1, 2, 4) // 1
```
## maxRecurse(...nums) ⇒ number
Write a function `maxRecurse` that
is the generalized `max` function
but uses recursion
| Param | Type |
| ------- | ------------------- |
| ...nums | number |
**Example**
```js
maxRecurse(1, 2, 4) // 4
```
## not(func) ⇒ function
Write a function `not` that
takes a function and returns
the negation of its result
| Param | Type |
| ----- | --------------------- |
| func | function |
**Example**
```js
const isOdd = (x) => x % 2 === 1
const isEven = not(isOdd)
isEven(1) // false
isEven(2) // true
```
## 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
| Param | Type |
| ------- | --------------------- |
| func | function |
| initial | any |
**Example**
```js
let add = acc(addb, 0)
add(1, 2, 4) // 7
let mul = acc(mulb, 1)
mul(1, 2, 4) // 8
```
## 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.
| Param | Type |
| ----- | --------------------- |
| func | function |
| start | number |
| end | number |
**Example**
```js
const addSecondToThird = accPartial(add, 1, 3)
addSecondToThird(1, 2, 4, 8) // [ 1, 6, 8 ]
```
## accRecurse(func, initial) ⇒ function
Write a function `accRecurse` that
does what `acc` does but uses recursion
| Param | Type |
| ------- | --------------------- |
| func | function |
| initial | number |
**Example**
```js
let add = accRecurse(addb, 0)
add(1, 2, 4) // 7
let mul = accRecurse(mulb, 1)
mul(1, 2, 4) // 8
```
## fill(num) ⇒ array
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**
```js
fill(3) // [ 3, 3, 3 ]
```
## fillRecurse(num) ⇒ array
Write a function `fillRecurse` that
does what `fill` does but uses recursion
| Param | Type |
| ----- | ------------------- |
| num | number |
**Example**
```js
fillRecurse(3) // [ 3, 3, 3 ]
```
## set(...args) ⇒ array
Write a function `set` that
is given a list of arguments
and returns an array with
all duplicates removed
| Param | Type |
| ------- | ---------------- |
| ...args | any |
**Example**
```js
let oneAndTwo = set(1, 1, 1, 2, 2, 2) // [ 1, 2 ]
```
## identityf(x) ⇒ function
Write a function `identityf`
that takes an argument and
returns a function that
returns that argument
| Param | Type |
| ----- | ---------------- |
| x | any |
**Example**
```js
let three = identityf(3)
three() // 3
```
## addf(a) ⇒ function
Write a function `addf` that
adds from two invocations
| Param | Type |
| ----- | ------------------- |
| a | number |
**Example**
```js
addf(3)(4) // 7
```
## liftf(binary) ⇒ function
Write a function `liftf` that
takes a binary function, and
makes it callable with two
invocations
| Param | Type |
| ------ | --------------------- |
| binary | function |
**Example**
```js
let addf = liftf(addb)
addf(3)(4) // 7
liftf(mulb)(5)(6) // 30
```
## pure(x, y) ⇒ array
Write a [pure](https://en.wikipedia.org/wiki/Pure_function) function `pure` that
is a wrapper arround the impure
function `impure`
```js
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**
```js
pure(20, 5) // [ 6, 120 ]
pure(25, 6) // [ 7, 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
| Param | Type |
| ------ | --------------------- |
| binary | function |
| a | any |
**Example**
```js
let add3 = curryb(addb, 3)
add3(4) // 7
curryb(mulb, 5)(6) // 30
```
## curry(func, ...outer) ⇒ function
Write a function `curry` that
is generalized for any amount
of arguments
| Param | Type |
| -------- | --------------------- |
| func | function |
| ...outer | any |
**Example**
```js
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
```
## inc(x) ⇒ number
Without writting any new functions,
show multiple ways to create the `inc`
function
| Param | Type |
| ----- | ------------------- |
| x | number |
**Example**
```js
inc(5) // 6
inc(inc(5)) // 7
```
## 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
| Param | Type |
| ------ | --------------------- |
| binary | function |
**Example**
```js
let doubl = twiceUnary(addb)
doubl(11) // 22
let square = twiceUnary(mulb)
square(11) // 121
```
## doubl(x) ⇒ number
Use the function `twiceUnary` to
create the `doubl` function
| Param | Type |
| ----- | ------------------- |
| x | number |
**Example**
```js
doubl(11) // 22
```
## square(x) ⇒ number
Use the function `twiceUnary` to
create the `square` function
| Param | Type |
| ----- | ------------------- |
| x | number |
**Example**
```js
square(11) // 121
```
## twice(x) ⇒ any
Write a function `twice` that
is generalized for any amount
of arguments
| Param | Type |
| ----- | --------------------- |
| x | function |
**Example**
```js
let doubleSum = twice(add)
doubleSum(1, 2, 4) // 1 + 2 + 4 + 1 + 2 + 4 = 14
```
## reverseb(binary) ⇒ function
Write a function `reverseb` that
reverses the arguments of a
binary function
| Param | Type |
| ------ | --------------------- |
| binary | function |
**Example**
```js
let bus = reverseb(subb)
bus(3, 2) // -1
```
## reverse(func) ⇒ function
Write a function `reverse` that
is generalized for any amount
of arguments
| Param | Type |
| ----- | --------------------- |
| func | function |
**Example**
```js
reverse(sub)(1, 2, 4) // 4 - 2 - 1 = 1
```
## composeuTwo(unary1, unary2) ⇒ function
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**
```js
composeuTwo(doubl, square)(5) // (5 * 2)^2 = 100
```
## composeu(...funcs) ⇒ any
Write a function `composeu` that
is generalized for any amount
of arguments
| Param | Type |
| -------- | --------------------- |
| ...funcs | function |
**Example**
```js
composeu(doubl, square, identity, curry(add, 1, 2))(5) // (5 * 2)^2 + 1 + 2 = 103
```
## composeb(binary1, binary2) ⇒ function
Write a function `composeb` that
takes two binary functions and
returns a function that calls
them both
| Param | Type |
| ------- | --------------------- |
| binary1 | function |
| binary2 | function |
**Example**
```js
composeb(addb, mulb)(2, 3, 7) // (2 + 3) * 7 = 35
```
## composeTwo(func1, func2) ⇒ function
Write a function `composeTwo` that
takes two functions and returns a
function that calls them both
| Param | Type |
| ----- | --------------------- |
| func1 | function |
| func2 | function |
**Example**
```js
composeTwo(add, square)(2, 3, 7, 5) // (2 + 3 + 7 + 5)^2 = 289
```
## 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
| Param | Type |
| -------- | --------------------- |
| ...funcs | function |
**Example**
```js
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
```
## limitb(binary, lmt) ⇒ function
Write a function `limitb`
that allows a binary function
to be called a limited number
of times
| Param | Type |
| ------ | --------------------- |
| binary | function |
| lmt | number |
**Example**
```js
let addLmtb = limitb(addb, 1)
addLmtb(3, 4) // 7
addLmtb(3, 5) // undefined
```
## limit(func, lmt) ⇒ function
Write a function `limit` that
is generalized for any amount
of arguments
| Param | Type |
| ----- | --------------------- |
| func | function |
| lmt | number |
**Example**
```js
let addLmt = limit(add, 1)
addLmt(1, 2, 4) // 7
addLmt(3, 5, 9, 2) // undefined
```
## genFrom(x) ⇒ function
Write a function `genFrom` that
produces a generator that will
produces a series of values. Follows the [iterator protocol](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols#the_iterator_protocol) for the returned format.
| Param | Type |
| ----- | ------------------- |
| x | number |
**Example**
```js
let index = genFrom(0)
index.next().value // 0
index.next().value // 1
index.next().value // 2
```
## 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
| Param | Type |
| ----- | --------------------- |
| gen | function |
| lmt | number |
**Example**
```js
let index = genTo(genFrom(1), 3)
index.next().value // 1
index.next().value // 2
index.next().value // undefined
```
## genFromTo(start, end) ⇒ function
Write a function `genFromTo` that
produces a generator that will
produce values in a range
| Param | Type |
| ----- | ------------------- |
| start | number |
| end | number |
**Example**
```js
let index = genFromTo(0, 3)
index.next().value // 0
index.next().value // 1
index.next().value // 2
index.next().value // undefined
```
## 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
| Param | Type |
| ----- | --------------------- |
| array | array |
| gen | function |
**Example**
```js
let ele = elementGen(['a', 'b', 'c', 'd'], genFromTo(1, 3))
ele.next().value // 'b'
ele.next().value // 'c'
ele.next().value // undefined
```
## element(array, gen) ⇒ function
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**
```js
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
```
## 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
| Param | Type |
| ----- | --------------------- |
| gen | function |
| array | array |
**Example**
```js
let array = []
let col = collect(genFromTo(0, 2), array)
col.next().value // 0
col.next().value // 1
col.next().value // undefined
array // [0, 1]
```
## 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
| Param | Type |
| --------- | --------------------- |
| gen | function |
| predicate | function |
**Example**
```js
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
```
## filterTail(gen, predicate) ⇒ function
Write a function `filterTail` that uses
tail-recursion to perform the filtering
| Param | Type |
| --------- | --------------------- |
| gen | function |
| predicate | function |
**Example**
```js
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
```
## concatTwo(gen1, gen2) ⇒ function
Write a function `concatTwo` that takes
two generators and produces a generator
that combines the sequences
| Param | Type |
| ----- | --------------------- |
| gen1 | function |
| gen2 | function |
**Example**
```js
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
```
## concat(...gens) ⇒ function
Write a function `concat` that
is generalized for any amount
of arguments
| Param | Type |
| ------- | --------------------- |
| ...gens | function |
**Example**
```js
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
```
## concatTail(...gens) ⇒ function
Write a function `concatTail` that uses
tail-recursion to perform the concating
| Param | Type |
| ------- | --------------------- |
| ...gens | function |
**Example**
```js
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
```
## gensymf(symbol) ⇒ function
Write a function `gensymf` that
makes a function that generates
unique symbols
| Param | Type |
| ------ | ------------------- |
| symbol | string |
**Example**
```js
let genG = gensymf('G')
let genH = gensymf('H')
genG.next().value // 'G1'
genH.next().value // 'H1'
genG.next().value // 'G2'
genH.next().value // 'H2'
```
## gensymff(unary, seed) ⇒ function
Write a function `gensymff` that
takes a unary function and a
seed and returns a `gensymf`
| Param | Type |
| ----- | --------------------- |
| unary | function |
| seed | number |
**Example**
```js
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'
```
## fibonaccif(first, second) ⇒ function
Write a function `fibonaccif` that
returns a generator that will
return the next fibonacci number
| Param | Type |
| ------ | ------------------- |
| first | number |
| second | number |
**Example**
```js
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
```
## counter(i) ⇒ object
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**
```js
let obj = counter(10)
let { up, down } = obj
up() // 11
down() // 10
down() // 9
up() // 10
```
## revocableb(binary) ⇒ object
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**
```js
let rev = revocableb(addb)
rev.invoke(3, 4) // 7
rev.revoke()
rev.invoke(5, 7) // undefined
```
## revocable(func) ⇒ object
Write a function `revocable` that
is generalized for any amount of
arguments
| Param | Type |
| ----- | --------------------- |
| func | function |
**Example**
```js
let rev = revocable(add)
rev.invoke(3, 4) // 7
rev.revoke()
rev.invoke(5, 7) // undefined
```
## 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
| Param | Type |
| ----- | ------------------- |
| array | array |
| prop | string |
**Example**
```js
let people = [{ name: 'john' }, { name: 'bob' }]
let names = extract(people, 'name') // ['john', 'bob']
```
## m(value, source) ⇒ object
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**
```js
m(1) // {value:1, source:"1"}
m(Math.PI, 'pi') // {value:3.14159..., source:"pi"}
```
## addmTwo(m1, m2) ⇒ object
Write a function `addmTwo` that
adds two `m` objects and
returns an `m` object
| Param | Type |
| ----- | --------------------- |
| m1 | function |
| m2 | function |
**Example**
```js
addmTwo(m(3), m(4)) // {value:7, source:"(3+4)"}
addmTwo(m(1), m(Math.PI, 'pi')) // {value:4.14159..., source:"(1+pi)"}
```
## addm(...ms) ⇒ object
Write a function `addm` that
is generalized for any amount of
arguments
| Param | Type |
| ----- | --------------------- |
| ...ms | function |
**Example**
```js
addm(m(1), m(2), m(4)) // {value:7, source:"(1+2+4)"}
```
## liftmbM(binary, op) ⇒ object
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**
```js
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)"}
```
## liftmb(binary, op) ⇒ object
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**
```js
let addmb = liftmb(addb, '+')
addmb(3, 4) // {value:7, source:"(3+4)"}
```
## liftm(func, op) ⇒ object
Write a function `liftm` that
is generalized for any amount of
arguments
| Param | Type |
| ----- | --------------------- |
| func | function |
| op | string |
**Example**
```js
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)"}
```
## exp(value) ⇒ any
Write a function `exp` that
evaluates simple array
expressions
| Param | Type |
| ----- | ---------------- |
| value | any |
**Example**
```js
let sae = [mul, 1, 2, 4]
exp(sae) // 1 * 2 * 4 = 8
exp(42) // 42
```
## expn(value) ⇒ any
Write a function `expn`
that is a modified `exp` that
can evaluate nested array
expressions
| Param | Type |
| ----- | ---------------- |
| value | any |
**Example**
```js
let nae = [Math.sqrt, [add, [square, 3], [square, 4]]]
expn(nae) // sqrt(((3*3)+(4*4))) === 5
```
## addg(value) ⇒ number | undefined
Write a function `addg` that
adds from many invocations,
until it sees an empty
invocation
| Param | Type |
| ----- | ------------------- |
| value | number |
**Example**
```js
addg() // undefined
addg(2)() // 2
addg(2)(7)() // 9
addg(3)(0)(4)() // 7
addg(1)(2)(4)(8)() // 15
```
## liftg(binary) ⇒ function
Write a function `liftg` that
will take a binary function
and apply it to many invocations
| Param | Type |
| ------ | --------------------- |
| binary | function |
**Example**
```js
liftg(mulb)() // undefined
liftg(mulb)(3)() // 3
liftg(mulb)(3)(0)(4)() // 0
liftg(mulb)(1)(2)(4)(8)() // 64
```
## arrayg(value) ⇒ array
Write a function `arrayg` that
will build an array from many
invocations
| Param | Type |
| ----- | ---------------- |
| value | any |
**Example**
```js
arrayg() // []
arrayg(3)() // [3]
arrayg(3)(4)(5)() // [3, 4, 5]
```
## continuizeu(unary) ⇒ function
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**
```js
let sqrtc = continuizeu(Math.sqrt)
sqrtc(console.log, 81) // logs '9'
```
## continuize(func) ⇒ function
Write a function `continuize`
that takes a function and
returns a function that
takes a callback and arguments
| Param | Type |
| ----- | --------------------- |
| func | function |
**Example**
```js
let mullc = continuize(mul)
mullc(console.log, 81, 4, 2) // logs '648'
```
## vector()
Make an array wrapper object
with methods `get`, `store`,
and `append`, such that an
attacker cannot get access
to the private array
**Example**
```js
let v = vector()
v.append(7)
v.store(1, 8)
v.get(0) // 7
v.get(1) // 8
```
## exploitVector()
Let's assume your `vector`
implementation looks like
something like this:
```js
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**
```js
let v = vector()
v.append(1)
v.append(2)
let internalData = exploitVector(v) // [1, 2]
```
## vectorSafe()
How would you rewrite `vector` to deal
with the issue from above?
**Example**
```js
let v = vectorSafe()
v.append(1)
v.append(2)
let internalData = exploitVector(v) // undefined
```
## pubsub()
Make a function `pubsub` that
makes a publish/subscribe object.
It will reliably deliver all
publications to all subscribers
in the right order.
**Example**
```js
let ps = pubsub()
ps.subscribe(console.log)
ps.publish('It works!') // logs 'It works!'
```
## mapRecurse(array, callback) ⇒ array
Make a function `mapRecurse` that
performs a transformation for each
element of a given array, recursively
| Param | Type |
| -------- | --------------------- |
| array | array |
| callback | function |
**Example**
```js
mapRecurse([1, 2, 3, 4], (x) => x * 2) // [ 2, 4, 6, 8 ]
```
## 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.
| Param | Type |
| --------- | --------------------- |
| array | array |
| predicate | function |
**Example**
```js
filterRecurse([1, 2, 3, 4], (x) => x % 2 === 0) // [ 2, 4 ]
```