An open API service indexing awesome lists of open source software.

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

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 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 generalized add function
but uses recursion




mulRecurse(...nums)number


Write a function mulRecurse that
is the generalized mul function
but uses recursion




minRecurse(...nums)number


Write a function minRecurse that
is the generalized min function
but uses recursion




maxRecurse(...nums)number


Write a function maxRecurse that
is the generalized max 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 what acc 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 what fill 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
function impure

```js
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 the doubl function




square(x)number


Use the function twiceUnary to
create the square 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
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.




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 a gensymf




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 an
invoke function that can invoke a
function and a revoke function
that disables the invoke 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 two m objects and
returns an m 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 on m objects




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




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 modified exp 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,
and append, 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 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?



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.



## 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 ]
```