ANDing on array of function - javascript

Given:
const a = () => true
const b = () => false
const t = [a, b]
How can I generate an additive AND:
a() && b()
In this case, it would return false.

You could reduce the array by using true as startValue and perform a logical AND && by using the result of the function call.
This approach keeps the value of the function calls.
const a = () => true
const b = () => false
const t = [a, b]
console.log(t.reduce((r, f) => r && f(), true));
Approach with a stored value for the result and a short circuit.
const AND = array => {
var result = true;
array.every(fn => result = result && fn());
return result;
};

Use array.every():
const a = () => true
const b = () => false
const t = [a, b]
console.log(t.every(f => f()));
This will only produce a boolean value, so if you were intending to get a different result as if short circuiting you'll have to use a reduce() solution or other.

In your case, using a() && b() will work perfectly. If you want to use the t array, you can do it like this: t[0]() && t[1](). However, if you want multiple inputs, I think it would be good to use an array function (Array.prototype.reduce):
t.reduce((previous, item) => previous && item(), true)

Use Array.find() to get the 1st function with a falsy value. If none found, take the last function in the array, and if the array is empty use the fallback function that returns undefined. Invoke the function that you got.
const fn = arr => (
arr.find(f => !f()) || arr[arr.length - 1] || (() => undefined)
)()
console.log(fn([() => true, () => false])) // false
console.log(fn([() => 1, () => 2])) // 2
console.log(fn([() => 1, () => 0, () => 2])) // 0
console.log(fn([])) // undefined

Related

Exit function on subfunction result

I wonder if there is a method to exit function based on other function output.
In other words: I have a function that evaluates some values and if they are fine returns them, otherwise causes a warning to user.
const verifier = () => {
const a = Number(document.querySelector("#a").value);
const b = Number(document.querySelector("#b").value);
if(isNaN(a) || isNaN(b)) {
console.log("Sent notification to user");
return
}
return [a, b]
}
Now, I use it multiple times, e.g.:
const adder = () => {
const [a,b] = verifier() || return; // <--- HERE!
console.log(a);
console.log(b);
}
In HERE: if verification function returns false / undefined / null I would like to exit my function prematurely, otherwise: assign to variables.
As I wrote in my comment, if you're willing to introduce an intermediary helper, you could write it as follows:
const verifier = () => {
const a = Number(document.querySelector("#a").value);
const b = Number(document.querySelector("#b").value);
if(isNaN(a) || isNaN(b)) {
console.log("Sent notification to user");
return;
}
return [a, b];
}
// helper that only calls `fn` if verifier does not return undefined
const ifVerified = (fn) => {
const values = verifier();
return undefined === values ? undefined : fn(values);
};
const adder = () => ifVerified(([a, b]) => {
// do something with a and b
});
You can't use return where an expression is expected, because return is a statement.
There are a bunch of other ways to do it, but they're all going to be clunkier than you're going to want. :-) For instance, you could have verifier return the NaN values and then test the result:
const verifier = () => {
const a = Number(document.querySelector("#a").value);
const b = Number(document.querySelector("#b").value);
if (isNaN(a) || isNaN(b)) {
console.log("Sent notification to user");
return [NaN, NaN];
}
return [a, b];
};
const adder = () => {
const [a,b] = verifier();
if (isNaN(a)) {
return;
}
console.log(a);
console.log(b);
};
Or you could leave verifier as it is and use nullish coalescing (quite new) at the point where you call it:
const adder = () => {
const [a, b] = verifier() ?? [];
if (a === undefined) {
return;
}
console.log(a);
console.log(b);
};
perhaps with an explicit flag value as a default:
const adder = () => {
const [a = null, b] = verifier() ?? [];
if (a === null) {
return;
}
console.log(a);
console.log(b);
};
Or store the returned array/undefined and test that:
const adder = () => {
const result = verifier();
if (!result) {
return;
}
const [a, b] = result;
console.log(a);
console.log(b);
};
But they all involve that if. (Or you could throw.)

Can javascript arrays imitate lisp lists ? implementing javascript version of accumulate-n function (SICP exercise 2.36)

I am implementing javascript version of accumulate-n function (SICP exercise 2.36)
However unlike scheme, javascript doesn't have nil indicator for arrays, which results in an extra "undefined" value in output array. Should I create a new "List" data structure which imitate Scheme lists or there are some tricks to get this done by native arrays in javascript
Here is the code I am working on
const accumulate = (op, init, sequence) => Array.prototype.reduce.call(sequence, op, init)
const map = (fn, sequence) => Array.prototype.map.call(sequence, fn)
const concat = (A, B) => Array.prototype.concat.call([], A, B)
const sum = (a, b) => a + b
const first = (sequence) => {
const [first, ...rest] = sequence
return first
}
const rest = (sequence) => {
const [first, ...rest] = sequence
return rest;
}
const isEmpty = sequence => sequence.length === 0
const accumulateN = (op, init, sequenceOfSequences) => {
if(isEmpty(first(sequenceOfSequences))) return;
return concat(accumulate(op, init, map(first, sequenceOfSequences)), accumulateN(op, init, map(rest, sequenceOfSequences)))
}
log(accumulateN(sum, 0, [[1,2,3], [4,5,6], [5,6,7]]))
//outputs [ 10, 13, 16, undefined ]

What is the initial value of the compose function's reduce function if no argument is passed to the first returned function?

I have tried to rewrite the compose function to print to the console with different arguments but I am still unable to figure it out. The first time the compose function is called arg is undefined. So the reduce function would use the first element of the array (console.clear()) as the initial value and that would be used as the argument for the next function, getCurrentTime.
When compose is called with convertToCivilianTime it uses the returned value from serializeClockTime as the argument for the first returned function in compose.
So how is compose called the first time with an undefined arg argument without causing an error?
const compose = (...fns) =>
(arg) =>
fns.reduce( (composed, f) => f(composed), arg)
const oneSecond = () => 1000
const getCurrentTime = () => new Date()
const clear = () => console.clear()
const log = message => console.log(message)
const serializeClockTime = date => ({
hours: date.getHours(),
minutes: date.getMinutes(),
seconds: date.getSeconds()
})
const civilianHours = clockTime => ({
...clockTime,
hours: ( clockTime.hours > 12 ) ? clockTime.hours - 12 : clockTime.hours
})
const appendAMPM = clockTime => ({
...clockTime,
ampm: ( clockTime.hours >= 12 ) ? "PM" : "AM"
})
const display = target => time => target(time)
const formatClock = format => time => format.replace('hh', time.hours).replace('mm', time.minutes).replace('ss', time.seconds).replace('tt', time.ampm)
const prependZero = key => clockTime => ({
...clockTime,
[key] : ( clockTime[key] < 10 ) ? "0" + clockTime[key] : clockTime[key]
})
const convertToCivilianTime = clockTime => compose(appendAMPM, civilianHours)(clockTime)
const doubleDigits = civilianTime => compose(
prependZero('hours'),
prependZero('minutes'),
prependZero('seconds')
)(civilianTime)
const startTicking = () => setInterval(compose(
clear,
getCurrentTime,
serializeClockTime,
convertToCivilianTime,
doubleDigits,
formatClock('hh:mm:ss tt'),
display(log)
),
oneSecond()
)
startTicking()
Passing undefined as the initial argument to reduce does not mean "use the default initial argument" (first element of the array) but just "use undefined as the initial argument":
const arr = [1, 2, 3];
const traceSum = (a, b) => {
console.log(a, b)
return a + b
};
console.log("reduce without initial argument:", arr.reduce(traceSum));
console.log("reduce with initial argument:", arr.reduce(traceSum, 0));
console.log("reduce with initial argument undefined:", arr.reduce(traceSum, undefined));
So, it's safe to call a function created by compose, even if you don't supply an argument, since arg will simply be an explicity undefined and thus each function gets executed but the initial value that goes through them is undefined:
const compose = (...fns) =>
(arg) =>
fns.reduce( (composed, f) => f(composed), arg)
const trace = message => value => {
console.log(message, value);
return value;
}
const test = compose(trace("one"), trace("two"));
console.log(test("hello"));
console.log(test());
You just have to make sure that your composed functions can work without an initial value:
const compose = (...fns) =>
(arg) =>
fns.reduce( (composed, f) => f(composed), arg)
const excited = str => str + "!";
const loud = str => str.toUpperCase();
const greet = () => "hey";
const shout = compose(loud, excited);
const shoutGreeting = compose(greet, shout);
console.log(shout("stop")); //works with initial value
console.log(shoutGreeting()); //works without initial value
console.log(shoutGreeting("hammer time")); //ignores initial value
console.log(shout()); //error - initial value expected
When no argument is passed as the initialValue of the reduce function, the first time, it will call the callback with the first two elements of the array.
For example:
[1, 2, 3, 4, 5].reduce((a, b) => {
console.log(a, ',', b, ',', a + b)
return a + b;
}
It will result in the following logs:
1 , 2 , 3
3 , 3 , 6
6 , 4 , 10
10 , 5 , 15

How to correctly serialize Javascript curried arrow functions?

const makeIncrementer = s=>a=>a+s
makeIncrementer(10).toString() // Prints 'a=>a+s'
which would make it impossible to de-serialize correctly (I would expect something like a=>a+10 instead.
Is there a way to do it right?
This is a great question. While I don't have a perfect answer, one way you could get details about the argument/s is to create a builder function that stores the necessary details for you. Unfortunately I can't figure out a way to know which internal variables relate to which values. If I figure out anything else i'll update:
const makeIncrementer = s => a => a + s
const builder = (fn, ...args) => {
return {
args,
curry: fn(...args)
}
}
var inc = builder(makeIncrementer, 10)
console.log(inc) // logs args and function details
console.log(inc.curry(5)) // 15
UPDATE: It will be a mammoth task, but I realised, that if you expand on the builder idea above, you could write/use a function string parser, that could take the given args, and the outer function, and rewrite the log to a serialised version. I have a demo below, but it will not work in real use cases!. I have done a simple string find/replace, while you will need to use an actual function parser to replace correctly. This is just an example of how you could do it. Note that I also used two incrementer variables just to show how to do multiples.
function replaceAll(str, find, replace) {
return str.replace(new RegExp(find, 'g'), replace)
}
const makeIncrementer = (a, b) => c => c + a + b
const builder = (fn, ...args) => {
// get the outer function argument list
var outers = fn.toString().split('=>')[0]
// remove potential brackets and spaces
outers = outers.replace(/\(|\)/g,'').split(',').map(i => i.trim())
// relate the args to the values
var relations = outers.map((name, i) => ({ name, value: args[i] }))
// create the curry
var curry = fn(...args)
// attempt to replace the string rep variables with their true values
// NOTE: **this is a simplistic example and will break easily**
var serialised = curry.toString()
relations.forEach(r => serialised = replaceAll(serialised, r.name, r.value))
return {
relations,
serialised,
curry: fn(...args)
}
}
var inc = builder(makeIncrementer, 10, 5)
console.log(inc) // shows args, serialised function, and curry
console.log(inc.curry(4)) // 19
You shouldn't serialize/parse function bodies since this quickly leads to security vulnerabilities. Serializing a closure means to serialize its local state, that is you have to make the closure's free variables visible for the surrounding scope:
const RetrieveArgs = Symbol();
const metaApply = f => x => {
const r = f(x);
if (typeof r === "function") {
if (f[RetrieveArgs])
r[RetrieveArgs] = Object.assign({}, f[RetrieveArgs], {x});
else r[RetrieveArgs] = {x};
}
return r;
}
const add = m => n => m + n,
f = metaApply(add) (10);
console.log(
JSON.stringify(f[RetrieveArgs]) // {"x":10}
);
const map = f => xs => xs.map(f)
g = metaApply(map) (n => n + 1);
console.log(
JSON.stringify(g[RetrieveArgs]) // doesn't work with higher order functions
);
I use a Symbol in order that the new property doesn't interfere with other parts of your program.
As mentioned in the code you still cannot serialize higher order functions.
Combining ideas from the two answers so far, I managed to produce something that works (though I haven't tested it thoroughly):
const removeParentheses = s => {
let match = /^\((.*)\)$/.exec(s.trim());
return match ? match[1] : s;
}
function serializable(fn, boundArgs = {}) {
if (typeof fn !== 'function') return fn;
if (fn.toJSON !== undefined) return fn;
const definition = fn.toString();
const argNames = removeParentheses(definition.split('=>', 1)[0]).split(',').map(s => s.trim());
let wrapper = (...args) => {
const r = fn(...args);
if (typeof r === "function") {
let boundArgsFor_r = Object.assign({}, boundArgs);
argNames.forEach((name, i) => {
boundArgsFor_r[name] = serializable(args[i]);
});
return serializable(r, boundArgsFor_r);
}
return r;
}
wrapper.toJSON = function () {
return { function: { body: definition, bound: boundArgs } };
}
return wrapper;
}
const add = m => m1 => n => m + n * m1,
fn = serializable(add)(10)(20);
let ser1, ser2;
console.log(
ser1 = JSON.stringify(fn) // {"function":{"body":"n => m + n * m1","bound":{"m":10,"m1":20}}}
);
const map = fn => xs => xs.map(fn),
g = serializable(map)(n => n + 1);
console.log(
ser2 = JSON.stringify(g) // {"function":{"body":"xs => xs.map(fn)","bound":{"fn":{"function":{"body":"n => n + 1","bound":{}}}}}}
);
const reviver = (key, value) => {
if (typeof value === 'object' && 'function' in value) {
const f = value.function;
return eval(`({${Object.keys(f.bound).join(',')}}) => (${f.body})`)(f.bound);
}
return value;
}
const rev1 = JSON.parse(ser1, reviver);
console.log(rev1(5)); // 110
const rev2 = JSON.parse(ser2, reviver);
console.log(rev2([1, 2, 3])); // [2, 3, 4]
This works for arrow functions, that do not have default initializers for the arguments. It supports higher order functions as well.
One still has to be able to wrap the original function into serializable before applying it to any arguments though.
Thank you #MattWay and #ftor for valuable input !

How to get a functions's body as string?

I want to know how to convert a function's body into a string?
function A(){
alert(1);
}
output = eval(A).toString() // this will come with function A(){ ~ }
//output of output -> function A(){ alert(1); }
//How can I make output into alert(1); only???
If you're going to do something ugly, do it with regex:
A.toString().match(/function[^{]+\{([\s\S]*)\}$/)[1];
Don't use a regexp.
const getBody = (string) => string.substring(
string.indexOf("{") + 1,
string.lastIndexOf("}")
)
const f = () => { return 'yo' }
const g = function (some, params) { return 'hi' }
const h = () => "boom"
console.log(getBody(f.toString()))
console.log(getBody(g.toString()))
console.log(getBody(h.toString())) // fail !
You could just stringify the function and extract the body by removing everything else:
A.toString().replace(/^function\s*\S+\s*\([^)]*\)\s*\{|\}$/g, "");
However, there is no good reason to do that and toString actually doesn't work in all environments.
Currently, developers are using arrow functions with the new releases of Ecmascript.
Hence, I would like to share the answer here which is the answer of Frank
function getArrowFunctionBody(f) {
const matches = f.toString().match(/^(?:\s*\(?(?:\s*\w*\s*,?\s*)*\)?\s*?=>\s*){?([\s\S]*)}?$/);
if (!matches) {
return null;
}
const firstPass = matches[1];
// Needed because the RegExp doesn't handle the last '}'.
const secondPass =
(firstPass.match(/{/g) || []).length === (firstPass.match(/}/g) || []).length - 1 ?
firstPass.slice(0, firstPass.lastIndexOf('}')) :
firstPass
return secondPass;
}
const K = (x) => (y) => x;
const I = (x) => (x);
const V = (x) => (y) => (z) => z(x)(y);
const f = (a, b) => {
const c = a + b;
return c;
};
const empty = () => { return undefined; };
console.log(getArrowFunctionBody(K));
console.log(getArrowFunctionBody(I));
console.log(getArrowFunctionBody(V));
console.log(getArrowFunctionBody(f));
console.log(getArrowFunctionBody(empty));
Original question here
This coud be what youre looking for
const toString = (func) => `(${func.toString()})()`
console.log(toString(() => {
console.log("Hello world")
}))
This will execute the function.

Categories

Resources