I have an object foo that I want to call as a function foo(...). I can do that like this:
foo = n => n * foo.factor;
foo.factor = 2;
foo(2) // returns 4
But for this to work I need to write the function (n => n * foo.factor) before other properties. How can I write it after? I want to do something like this:
foo = { factor: 2 }
// write function
foo(2) // returns 4
Maybe use a small utility:
const functionize = (obj, fn) => Object.assign(fn, obj);
So one can do:
let foo = { factor: 2 };
foo = functionize(foo, n => n * foo.factor);
foo(2);
Or you just use a regular function:
foo.factor = 2;
function foo(n) { return foo.factor * n; }
I wish there was a way to define my object as a function and then later change its body...
const foo = (...args) => (foo.body || () => null)(...args);
foo.factor = 2;
foo.body = n => foo.factor * n;
foo(2);
You could do it with a simple helper:
const annotate = (f, annotations) => {
Object.assign(f, annotations);
return f;
};
...which you'd use like this:
foo = annotate(n => n * foo.factor, {factor: 2});
foo(2); // returns 4
But I wouldn't. Instead, I'd create a function builder:
const makeFoo = factor => n => n * factor;
and then:
const foo = makeFoo(2);
foo(2); // returns 4
Live example:
const makeFoo = factor => n => n * factor;
const foo2 = makeFoo(2);
console.log(foo2(2)); // returns 4
const foo4 = makeFoo(4);
console.log(foo4(2)); // returns 8
Related
I have 5 functions: func1(), func2(), func3(), func4(), func5(). I need to implement the compositionFunc() function, which can take any number of functions as arguments, and create a composition from them. The compositionFunc() function takes my 5 functions as arguments. The compositionFunc() function returns a function that takes its initial value as an argument. This nested function successively passing through an array of functions with each iteration returns the result of calling the accumulated value of the current function-argument. The result of one function can be passed as an argument to another function. How can i do this?
const func1 = (arg1) => {
return arg1;
};
const func2 = (arg2) => {
return arg2;
};
const func3 = (arg3) => {
return arg3;
};
const func4 = (arg4) => {
return arg4;
};
const func5 = (arg5) => {
return arg5;
};
const compositionFunc = () => {
...
};
you can define a function like this
const pipe = (...functions) => args => functions.reduce((res, f) => f(res), args)
const combine = (...functions) => args => functions.reduceRight((res, f) => f(res), args)
const plus1 = x => x + 1
const double = x => x * 2
const pipeFunction = pipe(plus1, double)
const combineFunction = combine(plus1, double)
console.log(combineFunction(1)) // (1 * 2) + 1
console.log(pipeFunction(1)) // (1 + 1) * 2
A simple reduce can accomplish that:
function pipe(input, ...func) {
return func.reduce((a, f) => f(a), input);
}
You pass it an initial value + chain of functions.
Example:
function f1(val) {
return val + 1;
}
function f2(val) {
return val * 10;
}
console.log(pipe(2, f1, f2)); //=> 30
Below are three functions that need to be composed and give us the output 30:
const add = (a) => a + 10;
const mul = (a) => a * 10;
const divide = (a) => a / 5;
// How to implement `compositionFunction`?
compositionFunction(add, mul, divide)(5);
//=> 30
Expected output is 30 because:
5 + 10 = 15
15 * 10 = 150
150 / 5 = 30
Something like this
const add = (a) => a + 10 ;
const mul = (a) => a * 10 ;
const divide = (a) => a / 5 ;
// How to use this function -----
const customComposeFn = (...f) => v => f.reduce((res, f) => f(res), v)
console.log(customComposeFn(add, mul, divide)(5));
There are two flavours of function composition:
left-to-right function composition aka pipe
right-to-left function composition aka compose
Here's a recursive implementation just for fun:
This assumes that there are at least two functions to compose
const compose = (...fn) => {
const [[f, g], x] = [fn.slice(-2), fn.slice(0, -2)];
const h = a => f(g(a));
return x.length ? compose(...x, h) : h;
}
const pipe = (...fn) => {
const [f, g, ...x] = fn;
const h = a => g(f(a));
return x.length ? pipe(h, ...x) : h;
}
Let's try:
const foo = x => x + 'foo';
const bar = x => x + 'bar';
const baz = x => x + 'baz';
pipe(foo, bar, baz)('');
//=> 'foobarbaz'
compose(foo, bar, baz)('');
//=> 'bazbarfoo'
const add = (a) => a + 10;
const mul = (a) => a * 10;
const divide = (a) => a / 5;
const customComposeFn = (...fn) => {
return function (arg) {
if (fn.length > 0) {
const output = fn[0](arg);
return customComposeFn(...fn.splice(1))(output);
} else {
return arg;
}
};
};
const res = customComposeFn(add, mul, divide)(5);
console.log(`res`, res);
Here's what I would do:
function customComposeFn(...funcs) {
return function(arg) {
let f, res = arg;
while (f = funcs.shift()) {
res = f(res)
}
return res;
}
}
const add = a => a + 10;
const mul = a => a * 10;
const divide = a => a / 5;
// How to use this function -----
console.log(customComposeFn(add, mul, divide)(5));
I am trying to re-implement function composition using reduceRight. Here is a function composition that I am trying to re-implement:
const compose = function([func1, func2, func3]) {
return function(value1, value2) {
return func1(func2(func3(value1, value2)));
};
};
const func3 = (x, y) => {
return y > 0 ? x + 3 : x - 3;
};
const func2 = x => {
return x ** 2;
};
const func1 = x => {
return x - 8;
};
const fn = compose([func1, func2, func3]);
console.log(fn('3', 1)); // 1081
console.log(fn('3', -1)); // -8
The following code is re-implementation of the above function. It looks like the argument y is getting undefined I am not sure why.
const compose = (...args) => value =>
args.reduceRight((acc, fn) => fn(acc), value);
const func3 = (x, y) => {
return y > 0 ? x + 3 : x - 3;
};
const func2 = x => {
return x ** 2;
};
const func1 = x => {
return x - 8;
};
const fnOne = compose(
func1,
func2,
func3
)('3', 1);
console.log(fnOne);//-8
const fnTwo = compose(
func1,
func2,
func3
)('3', -1);
console.log(fnTwo);//-8
Similar to compose, you could use rest parameter syntax get an an array of values. Then destructure the func3 arguments to get x and y like this:
const compose = (...args) => (...values) =>
args.reduceRight((acc, fn) => fn(acc), values);
// an array of values is passed here
// destructure to get the x and y values
const func3 = ([x, y]) => y > 0 ? x + 3 : x - 3;
const func2 = x => x ** 2;
const func1 = x => x - 8;
const fnOne = compose(
func1,
func2,
func3
)('3', 1);
console.log(fnOne);//1081
const fnTwo = compose(
func1,
func2,
func3
)('3', -1);
console.log(fnTwo);//-8
I have code like:
var addX = (e) => return e+1;
I am calling like:
[1,2,3].map(addX);
Can I make "1" dynamic? Like:
[1,2,3].map(addX(2)); //this wont work, in this case it should add 2
You need a closure over e and return a function with one parameter for the callback.
var addX = x => v => x + v;
console.log([1, 2, 3].map(addX(2)));
You can use currying like this:
var addX = n => e => e + n;
console.log([1,2,3].map(addX(2)));
console.log([1,2,3].map(addX(10)));
What this does is, you pass the number (n) that you want to be added to the function and it returns a new function which adds that number to it's argument (e) (each element when using map)
You can use bind(thisArg, argument1) to send an extra parameter
var addX = (a, b) => a+b;
console.log("2", [1,2,3].map(addX.bind(Array, 2)))
console.log("5", [1,2,3].map(addX.bind(Array, 5)))
The this argument really does not matter in this case. I just put Array there, it can be this, null, etc.
You can create a function to return a function that takes your add amount.
Here is an example below.
var addX = (addbit) => (e) => e + addbit;
console.log([1,2,3].map(addX(2)));
I would do something like this :)
var addX = (e) => e+1;
[1,2,3].map(num => addX(num))
Several utility libraries like Lodash, Underscore, and Ramda provide a curry() utility function that takes a function and returns a new version of that function that can take the same arguments one at a time, a few at a time, or all at once.
This means that you can create an add function that can either add two numbers right away add(4, 5) or that can "pre-bake" a function with one of the values included: const increment = add(1); console.log(increment(5));
const add = _.curry((x, y) => x + y);
console.log(add(6, 7));
console.log([1,2,3].map(add(10)));
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.min.js"></script>
If you don't want to include a whole library just for this purpose, you can also use this standalone version of curry:
var curryN = (function () {
var slice = Function.prototype.call.bind(Array.prototype.slice);
var bindArr = function (f, arr) { return f.bind.apply(f, [{}].concat(arr)); };
return function curryN(argCount, func) {
return function fn() {
var args = slice(arguments, 0, argCount);
return args.length === argCount
? func.apply({}, args)
: bindArr(fn, args);
};
};
})();
var curry = function curry(func) { return curryN(func.length, func); };
const add = curry((x, y) => x + y);
console.log(add(6, 7));
console.log([1,2,3].map(add(10)));
You can use closure for that:
var addX = inc => e => e + inc;
var res = [1,2,3].map(addX(2));
console.log(res);
EXPLANATION
var addX = inc => e => e + inc;
Is the equivalent of:
var addX = function(inc) {
return function(e) {
return e + inc;
}
}
So addX(2) returns the callback function(e) { return e + 2 } and it's the callback used by array.map
I have a generator called generateNumbers in JavaScript and another generator generateLargerNumbers which takes each value generated by generateNumbers and applies a function addOne to it, as such:
function addOne(value) {
return value + 1
}
function* generateNumbers() {
yield 1
yield 2
yield 3
}
function* generateLargerNumbers() {
for (const number of generateNumbers()) {
yield addOne(number)
}
}
Is there any terser way to do this without building an array out of the generated values? I'm thinking something like:
function* generateLargerNumbers() {
yield* generateNumbers().map(addOne) // obviously doesn't work
}
higher-order generators
You can choose to manipulate the generator functions themselves
const Generator =
{
map: (f,g) => function* (...args)
{
for (const x of g (...args))
yield f (x)
},
filter: (f,g) => function* (...args)
{
for (const x of g (...args))
if (f (x))
yield x
}
}
// some functions !
const square = x =>
x * x
const isEven = x =>
(x & 1) === 0
// a generator !
const range = function* (x = 0, y = 1)
{
while (x < y)
yield x++
}
// higher order generator !
for (const x of Generator.map (square, Generator.filter (isEven, range)) (0,10))
console.log('evens squared', x)
higher-order iterators
Or you can choose to manipulate iterators
const Iterator =
{
map: (f, it) => function* ()
{
for (const x of it)
yield f (x)
} (),
filter: (f, it) => function* ()
{
for (const x of it)
if (f (x))
yield x
} ()
}
// some functions !
const square = x =>
x * x
const isEven = x =>
(x & 1) === 0
// a generator !
const range = function* (x = 0, y = 1)
{
while (x < y)
yield x++
}
// higher-order iterators !
for (const x of Iterator.map (square, Iterator.filter (isEven, range (0, 10))))
console.log('evens squared', x)
recommendation
In most cases, I think it's more practical to manipulate the iterator because of it's well-defined (albeit kludgy) interface. It allows you to do something like
Iterator.map (square, Iterator.filter (isEven, [10,11,12,13]))
Whereas the other approach is
Generator.map (square, Generator.filter (isEven, Array.from)) ([10,11,12,13])
Both have a use-case, but I find the former much nicer than the latter
persistent iterators
JavaScript's stateful iterators annoy me – each subsequent call to .next alters the internal state irreversibly.
But! there's nothing stopping you from making your own iterators tho and then creating an adapter to plug into JavaScript's stack-safe generator mechanism
If this interests you, you might like some of the other accompanying examples found here: Loop to a filesystem structure in my object to get all the files
The only gain isn't that we can reuse a persistent iterator, it's that with this implementation, subsequent reads are even faster than the first because of memoisation – score: JavaScript 0, Persistent Iterators 2
// -------------------------------------------------------------------
const Memo = (f, memo) => () =>
memo === undefined
? (memo = f (), memo)
: memo
// -------------------------------------------------------------------
const Yield = (value, next = Return) =>
({ done: false, value, next: Memo (next) })
const Return = value =>
({ done: true, value })
// -------------------------------------------------------------------
const MappedIterator = (f, it = Return ()) =>
it.done
? Return ()
: Yield (f (it.value), () => MappedIterator (f, it.next ()))
const FilteredIterator = (f, it = Return ()) =>
it.done
? Return ()
: f (it.value)
? Yield (it.value, () => FilteredIterator (f, it.next ()))
: FilteredIterator (f, it.next ())
// -------------------------------------------------------------------
const Generator = function* (it = Return ())
{
while (it.done === false)
(yield it.value, it = it.next ())
return it.value
}
// -------------------------------------------------------------------
const Range = (x = 0, y = 1) =>
x < y
? Yield (x, () => Range (x + 1, y))
: Return ()
const square = x =>
x * x
const isEven = x =>
(x & 1) === 0
// -------------------------------------------------------------------
for (const x of Generator (MappedIterator (square, FilteredIterator (isEven, Range (0,10)))))
console.log ('evens squared', x)
There isn't a built-in way to map over Generator objects, but you could roll your own function:
const Generator = Object.getPrototypeOf(function* () {});
Generator.prototype.map = function* (mapper, thisArg) {
for (const val of this) {
yield mapper.call(thisArg, val);
}
};
Now you can do:
function generateLargerNumbers() {
return generateNumbers().map(addOne);
}
const Generator = Object.getPrototypeOf(function* () {});
Generator.prototype.map = function* (mapper, thisArg) {
for (const val of this) {
yield mapper.call(thisArg, val);
}
};
function addOne(value) {
return value + 1
}
function* generateNumbers() {
yield 1
yield 2
yield 3
}
function generateLargerNumbers() {
return generateNumbers().map(addOne)
}
console.log(...generateLargerNumbers())
How about composing an iterator object, instead of using the nested generators?
function* generateNumbers(){
yield 1;
yield 2;
yield 3;
}
function generateGreaterNumbers(){
return { next(){ var r = this.gen.next(); r.value+=1; return r; }, gen: generateNumbers() };`
}
If you need to actually pass values to your generator then you can't do it with for...of, you have to pass each value through
const mapGenerator = (generatorFunc, mapper) =>
function*(...args) {
let gen = generatorFunc(...args),
i = 0,
value;
while (true) {
const it = gen.next(value);
if (it.done) return mapper(it.value, i);
value = yield mapper(it.value, i);
i++;
}
};
function* generator() {
console.log('generator received', yield 1);
console.log('generator received', yield 2);
console.log('generator received', yield 3);
return 4;
}
const mapGenerator = (generatorFunc, mapper) =>
function*(...args) {
let gen = generatorFunc(...args),
i = 0,
value;
while (true) {
const it = gen.next(value);
if (it.done) return mapper(it.value, i);
value = yield mapper(it.value, i);
i++;
}
};
const otherGenerator = mapGenerator(generator, x => x + 1)
const it = otherGenerator();
console.log(
it.next().value,
it.next('a').value,
it.next('b').value,
it.next('c').value
);