returning object that returns functions - javascript

I need to write a function in JavaScript that takes a number and returns an object that returns chainable functions (without using OOP).
Example:
func(3).not().not().equals(4)
would outputs false.
And:
func(5).equals(5)
would output: true
This is the code I have written:
const func = (obj) => {
const obj2 = {
not: () => {
return !obj
},
equals: (num) => {
return obj === num
}
}
return obj2
}
It works when I call func(3).not() or func(5).equals(5), but doesn't allow me to chain the functions so calling func(5).not().equals(5) returns an error saying that this is not a function.
What am I not seeing here?

That's a very weird way to compose functions. Let's think about what's actually happening.
func(3).not().not().equals(4)
// is equivalent to
not(not(equals(4)(3)))
// where
const not = x => !x;
const equals = x => y => x === y;
The simplest way to implement this chain would be as follows.
const equals = x => toBool(y => x === y);
const toBool = func => ({
not: () => toBool(x => !func(x)),
func
});
const example1 = equals(4).not().not().func(3);
const example2 = equals(5).func(5);
console.log(example1); // false
console.log(example2); // true
However, this is a forward chain. You want a backward chain. Unfortunately, there's a problem.
In a forward chain .func(x) marks the end of the chain.
In a backward chain .equals(x) marks the end of the chain.
This means that in a backward chain, you wouldn't be able to write the following expression.
func(3).not().not().equals(4).add(1)
// expected to be equivalent to
not(not(equals(4)(add(1)(3))))
// but actually equivalent to
not(not(equals(4)(3))).add(1)
// which evaluates to
false.add(1)
On the other hand, you would be able to do this quite easily using a forward chain.
const id = x => x;
const toNum = func => ({
add: x => toNum(y => x + func(y)),
equals: x => toBool(y => x === func(y)),
func
});
const toBool = func => ({
not: () => toBool(x => !func(x)),
func
});
const { add, equals } = toNum(id);
const example1 = equals(4).not().not().func(3);
const example2 = add(1).equals(4).not().not().func(3);
console.log(example1); // false
console.log(example2); // true
By the way, this is an object-oriented design pattern even though it doesn't make use of classes.
My advice would be to write plain old functions.
const add = (x, y) => x + y;
const equals = (x, y) => x === y;
const not = x => !x;
const example1 = not(not(equals(4, 3)));
const example2 = not(not(equals(4, add(1, 3))));
console.log(example1); // false
console.log(example2); // true
The simplest solutions are usually the best. Source: Occam's razor.

To return another object with the same methods that wraps the new value, simply call func again:
const func = (obj) => {
const obj2 = {
not: () => {
return func(!obj)
// ^^^^^^^^^^^^^^^^^
},
equals: (num) => {
return obj === num
}
}
return obj2
}
console.log(func(3).not().not().equals(4))
console.log(func(5).equals(5))
console.log(func(3).not())

You can use a closure to store both the initial input and the state of the operation:
const func = (input) => {
let not = false
const obj = {
not: () => {
not = !not
return obj
},
equals: (num) => {
return not ? input !== num : input === num
}
}
return obj;
}
console.log(func(5).not().equals(5))
console.log(func(5).not().not().equals(5))
console.log(func(5).not().equals(4))
console.log(func(5).not().not().equals(4))

You could take an object for return as interface and store value and negation.
var object = {
func: function (value) {
object.left = value;
return object;
},
not: function() {
object.negation = !object.negation;
return object;
},
equals: function (value) {
var result = value === object.value;
return object.negation ? !result : result;
}
},
func = object.func;
console.log(func(3).not().not().equals(4));

Related

How to create a composition from functions

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

Executing list of async functions

I have an exercise to make a function executeFunctions which takes as arguments a list of async functions and an argument, e.g. number.
The functions have to happen one after another, so if fun1 ends, fun2 needs to start with the value which was returned from fun1.
The problem is that I can't use async and await. I wanted to do it using reduce, but I guess that it wants to execute const res1 and go further before it returns a value (because of setTimeout).
Is there any way to do it without async and await?
const fun1 = function(value) {
return setTimeout(() => value*2, 3000)
}
const fun2 = function(value) {
return setTimeout(() => value*4, 3000)
}
const cb2 = (value) => {
return value*10
}
const executeFunctions = (funTab, cb) => (n) => {
const res1= funTab[0](n)
console.log(res1)
const resReduce = funTab.reduce((prev,curr) => {
const res2 = curr(prev)
return prev+res2
}, res1)
return cb(resReduce)
};
executeFunctions([fun1,fun2], cb2)(2)
We can use Promise-chaining:
const fun1 = function(value) {
return Promise.resolve(value * 2);
}
const fun2 = function(value) {
return Promise.resolve(value * 2);
}
const fun3 = function(value) {
return Promise.resolve(value * 2);
}
const executeFunctions = (funcList) => (n) => {
let chain = Promise.resolve(n); // initial value
for (let i = 0; i < funcList.length; i++) {
chain = chain.then(funcList[i]); // keep chaining
}
return chain; // last promise
};
const main = () => {
// we need to wait for the last promise in order to print the result
executeFunctions([fun1, fun2, fun3])(2).then(x => console.log('solution is:', x));
}
main() // prints: "solution is: 16"
or, we can also use a modified version of the suggested reduce solution, by changing the implementation of executeFunctions as follows (the rest of the code should remain as in the previous snippet):
const executeFunctions = (funcList) => (n) => {
const init = Promise.resolve(n);
const res = funcList.reduce((p, c) => {
return p.then(c)
}, init);
return res;
};

Assign anonymous injected method factory name of caller

I need the name function to be defined for use with another method further down so I need it to be dynamically named.
currently...
`use strict`;
const factory = () => () => {}
const method = factory();
method.name === undefined
&&
const factory = () => { const name = () => {}; return name }
const method = factory();
method.name === "name"
because...
`use strict`;
const factory = () => () => {}
factory() === () => {} // and () => {} is not a named method
But I want...
`use strict`;
const factory = () => () => {}
const method = factory();
method.name === "method"
this is extra description because stack overflow wants me to say more but I think that the problem is self-explanatory
Make your arrow function a traditional function:
const factory = () => function method() {}
If the name is to be dynamic, then we have to deal with the fact that a function's name property is read-only. The function definition could happen in a dynamic way (but that involves parsing), or we could create a proxy:
const factory = () => new Proxy(() => console.log("hello"), {
get(obj, prop) {
return prop === "name" ? "method" : prop;
}
});
const method = factory();
console.log(method.name);
method();
Variable name
In comments you explained that the dynamic name should be determined by the variable name (i.e. method), but:
There can be many variables referring to the same function, while a function has only one name -- so that leads to an unresolvable paradox.
Variable names only exist at parse time, not at execution time.
You can do that by creating an object with the dynamic name prop and assigning the function to that prop:
`use strict`;
const factory = s => (
{[s]: () => {}}[s]
)
const method = factory('blah');
console.log(method.name)
Does this work? You'd have to repeat the name, though, so not sure it totally gets what you're looking for
let factory = (name) => new Function(`return function ${name}() {}`)();
let method = factory("method");
method.name; // "method"
Building off of #trincot's answer, what was initially proposed is not possible.
However, here's what I went with for a sufficient alternative:
`use strict`;
// #trincot's answer
const renameFunction = (name, func) => new Proxy(func, {
get(obj, prop) {
return prop === "name" ? name : prop;
}
})
const identifyFunction = (obj) => {
if (typeof obj === "object") {
// because the object has the original defined as a property
// we can pull the name back out
const name = Object.keys(obj)[0];
const func = obj[name];
return renameFunction(name, func)
}
// if it's not an object then assume it's named and return
return obj
}
const useFooName = (foo) => {
let _foo = foo;
// only need to identify if it's an object
if (typeof _foo === "object") {
_foo = identifyFunction(foo)
}
// using both the function and its name
console.log(`${_foo.name} ${_foo()}`);
}
const factory = (func) => func;
const foo = factory(() => "bar");
useFooName(foo) // bar
useFooName({ foo }) // foo bar
This can be used dynamically as well...
`use strict`;
// #trincot's answer
const renameFunction = (name, func) => new Proxy(func, {
get(obj, prop) {
return prop === "name" ? name : prop;
}
})
const identifyFunction = (obj) => {
if (typeof obj === "object") {
// because the object has the original defined as a property
// we can pull the name back out
const name = Object.keys(obj)[0];
const func = obj[name];
return renameFunction(name, func)
}
// if it's not an object then assume it's named and return
return obj
}
// let there be a function that accepts and function bar
// and uses bar's name; for whatever reason you don't want to
// change this method
const useBarName = (bar) => `${bar.name} ${bar()}`
// let there also be an arbitrary amount of functions using this
const traditionalWay = () => {
const a = () => "b";
const c = () => "d";
const e = () => "f";
console.log([a, c, e].map(useBarName).join(" ")); // a b c d e f ...
}
// but instead of hard-coding the functions it'd be easier
// to just build a factory that did it automatically
const brokenWay = () => {
const factory = (letter) => () => letter;
const a = factory("b");
const c = factory("d");
const e = factory("f");
console.log([a, c, e].map(useBarName).join(" ")); // b d f ...
}
// so instead you can use the indentifyFunction to identify
// the anonymous methods
const newWay = () => {
const factory = (letter) => () => letter;
const a = factory("b");
const c = factory("d");
const e = factory("f");
console.log([{a}, {c}, {e}].map(identifyFunction).map(useBarName).join(" ")); // a b c d e f ...
}
traditionalWay();
brokenWay();
newWay();

How would I create an invert higher order function?

I need to create a higher-order function called invert. It should do the following:
Return a new function.
Take a function as its only argument.
The inner function should take any number of arguments and inverts a call to the passed function.
What I have so far is just http://prntscr.com/l0rma0 but it only works for functions with no arguments.
Hopefully, this should be enough:
function invert(fn) {
return (...args) => !fn(...args);
}
Here's the test case:
function invert(fn) {
return (...args) => !fn(...args);
}
// test 1
const returnsTrue = () => true;
const returnsFalse = invert(returnsTrue);
console.log( returnsFalse() === false );
// test 2
const isEven = x => x % 2 === 0;
const isOdd = invert(isEven);
console.log( isOdd(13) === true );
console.log( isOdd(10) === false );
// test 3
const isSumBiggerThan100 = (...args) => args.reduce((acc, val) => acc + val) > 100;
const isSumLessThanOrEqualTo100 = invert(isSumBiggerThan100);
console.log( isSumLessThanOrEqualTo100(10, 3, 8, 5, 4, 20) === true);
console.log( isSumLessThanOrEqualTo100(70, 10, 50, 23) === false)
const higherFunction = (something) => {
return function innerFunc(...params) {
return !something;
}
};
Do you mean something like that ?

const is undefined within reduce method

avgPrice(data) {
const min_price = data.min_price,
max_price = data.max_price;
console.log(min_price) //has value
let x = _.reduce(data.custom_pricing, (a, b) => {
a.min_price = Math.min(a.min_price, b.min_price);
a.max_price = Math.max(a.max_price, b.max_price);
}, { min_price:min_price, max_price:max_price });
}
What's wrong with my code above? I got min_price is undefined error. But my const min_price has value when I do console.log.
You have to return from reduce (return a so it can be used for the next iteration).
let x = _.reduce(data.custom_pricing, (a, b) => {
a.min_price = Math.min(a.min_price, b.min_price);
a.max_price = Math.max(a.max_price, b.max_price);
return a; //<<<<<
}, { min_price:min_price, max_price:max_price });
No mutation:
Although I don't see a reason why.
let x = _.reduce(data.custom_pricing, (a, b) =>
({ min_price: Math.min(a.min_price, b.min_price), max_price: Math.max(a.max_price, b.max_price) }), // create a new object and return it
{ min_price:min_price, max_price:max_price });

Categories