I am interested in the scenario where we have some function f which is recursive and which we are not provided the source code to.
I would like a function memoizer: Function -> Function which takes in say f and returns a function g such that g = f (in the sense they return the same value given the same arguments) which when called first checks if the called arguments are in its 'cache' (memory of results it has calculated before) and if so returns the result from this, otherwise it should compute f, should f call itself with some arguments, this is tantamount to calling g with those arguments and I would like that f first check if the cache of g contains those arguments and if so return the result from this, otherwise ...
This is easy (in Javascript) to do given the source code of f, I simply define memoize in the obvious way and do something like
let f = memoize((...args) => {/* source code of f */});
But this doesn't appeal to me at all (mainly because I might want a memoized and non memoized version of the same function and then I'd have to write the same function twice) and won't work if I don't know how to implement f.
In case it's not clear what I'm asking,
I would like a function memoize which takes a function such as
fact = n => n === 0 ? 1 : n * fact(n - 1);
And returns some new function g such that fact(n) = g(n) for all n and which for example when g(10) is computed stores the values of fact(0), ..., fact(10) which are computed while computing g(10) and then if I ask for say g(7) it finds the result in the cache and returns it to me.
I've thought that conceptually it's possible to detect when f is called since I have it's address and maybe I could replace all calls to f with a new function where I compute f and store the result and then pass the value on to where it would normally go. But I don't know how to do this (and it sounds unpleasant).
maybe I could replace all calls to f with a new function where I compute f and store the result and then pass the value on to where it would normally go.
This is actually very easy to do, as Bergi referred to in a comment.
// https://stackoverflow.com/questions/24488862/implementing-automatic-memoization-returns-a-closured-function-in-javascript/
function memoize(func) {
var memo = {};
var slice = Array.prototype.slice;
return function() {
var args = slice.call(arguments);
if (args in memo)
return memo[args];
else
return (memo[args] = func.apply(this, args));
}
}
function fib(n) {
if (n <= 1) return 1;
return fib(n - 1) + fib(n - 2);
}
fib = memoize(fib);
console.log(fib(100));
I might want a memoized and non memoized version of the same function and then I'd have to write the same function twice
Yes, you need to. The recursive call to fact(n - 1) inside the function can only refer to one fact function - either a memoized or an unmemoized one.
So what you need to do to avoid code duplication is define fact with the Y combinator:
const makeFact = rec => n => n === 0 ? 1 : n * rec(n - 1);
// ^^^ ^^^
const factA = Y(makeFact);
const factB = memoizingY(makeFact);
function Y(make) {
const f = make((...args) => f(...args)); // const f = make(f) is easier to understand
return f; // but doesn't work with eager evaluation
}
I'll leave the definition of memoizingY as an exercise to the reader :-)
Possibly simpler approach:
const makeFact = annotate => {
const f = annotate(n => n === 0 ? 1 : n * f(n - 1));
return f;
}
const factA = makeFact(identity);
const factB = makeFact(memoize);
In my limited experience, we do have access to JavaScript source code. We could thus attempt to generate new source code for the memoized function.
// Redefine Function.prototype.bind
// to provide access to bound objects.
// https://stackoverflow.com/questions/7616461/generate-a-hash-from-string-in-javascript
var _bind = Function.prototype.apply.bind(Function.prototype.bind);
Object.defineProperty(Function.prototype, 'bind', {
value: function(obj) {
var boundFunction = _bind(this, arguments);
boundFunction.boundObject = obj;
return boundFunction;
}
});
// Assumes the parameters for the function,
// f, can be consistently mapped.
function memo(f){
if (!(f instanceof Function))
throw TypeError('Argument is not an instance of Function.');
// Generate random variable names
// to avoid conflicts with unknown
// source code
function randomKey(numBytes=8){
let ranges = [[48, 10], [65, 26], [97, 26]];
let key = '_';
for (let i=0; i<numBytes; i++){
let idx = Math.floor(Math.random() * ranges.length);
key += String.fromCharCode(ranges[idx][0] + Math.random() * ranges[idx][1]);
}
return key;
}
let fName = f.name;
let boundObject;
let fCode;
const nativeCodeStr = '(){[nativecode]}';
// Possible Proxy
try {
fCode = f.toString();
} catch(error){
if (error.constructor == TypeError){
if (Function(`return ${ fName }.toString()`)() != nativeCodeStr){
throw TypeError(`Possible Proxy detected: function has a name but no accessible source code. Consider memoizing the target function, ${ fName }.`);
} else {
throw TypeError(`Function has a name but no accessible source code. Applying toString() to its name, ${ fName }, returns '[native code]'.`);
}
} else {
throw Error('Unexpected error calling toString on the argument.');
}
}
if (!fName){
throw Error('Function name is falsy.');
// Bound functions
// Assumes we've monkey-patched
// Function.prototype.bind previously
} else if (fCode.replace(/^[^(]+|\s+/g, '') == nativeCodeStr){
if (/^bound /.test(fName)){
fName = fName.substr(6);
boundObject = f.boundObject;
// Bound functions return '[native code]' for
// their toString method call so get the code
// from the original function.
fCode = Function(`return ${ fName }.toString()`)();
} else {
throw Error("Cannot access source code, '[native code]' provided.");
}
}
const fNameRegex = new RegExp('(\\W)' + fName + '(\\W)', 'g');
const cacheName = randomKey();
const recursionName = randomKey();
const keyName = randomKey();
fCode = fCode.replace(/[^\(]+/,'')
.replace(fNameRegex, '$1' + recursionName + '$2')
.replace(/return/g, `return ${ cacheName }[${ keyName }] =`)
.replace(/{/, `{\n const ${ keyName } = Array.from(arguments);\n\n if (${ cacheName }[${ keyName }])\n return ${ cacheName }[${ keyName }];\n`);
const code = `function(){\nconst ${ cacheName } = {};\n\nfunction ${ recursionName + fCode }\n\nreturn ${ recursionName }.apply(${ recursionName }, arguments);}`;
let g = Function('"use strict";return ' + code)();
if (boundObject){
let h = (g).bind(boundObject);
h.toString = () => code;
return h;
} else {
return g;
}
} // End memo function
function fib(n) {
if (n <= 1) return 1;
return fib(n - 1) + fib(n - 2);
}
const h = fib.bind({a: 37});
const g = memo(h);
console.log(`g(100): ${ g(100) }`);
console.log(`g.boundObject:`, g.boundObject);
console.log(`g.toString():`, g.toString());
try{
memo(function(){});
} catch(e){
console.log('Caught error memoizing anonymous function.', e)
}
const p = new Proxy(fib, {
apply: function(target, that, args){
console.log('Proxied fib called.');
return target.apply(target, args);
}
});
console.log('Calling proxied fib.');
console.log(`p(2):`, p(2));
let memoP;
try {
memoP = memo(p);
} catch (e){
console.log('Caught error memoizing proxied function.', e)
}
Related
I'm trying to create a function that accepts two callbacks and a value that will return a boolean indicating if the passing the value into the first function, and then passing the resulting output into the second function, yields the same output as the same operation in reverse (passing the value into the second function and then passing the output into the first function).
I get the following error and I believe it is probably due to scoping but not sure how to resolve it: Reference Error on line 206: ouput2 is not defined
function commutative(func1, func2, value) {
//check to see if invoking cb1 on value then passing output to cb2 as cb2 => cb1
function func1() {
let output1 = func1(value);
return output1;
}
function func2() {
let output2 = func2(output1);
return output2;
}
function reverseOrder() {
let output3 = func2(value);
let output4 = func1(output3);
}
//return boolean
if (ouput2 === output4) {
return true;
} else {
return false;
}
}
// Test cases:
const multBy3 = n => n * 3;
const divBy4 = n => n / 4;
const subtract5 = n => n - 5;
console.log(commutative(multBy3, divBy4, 11)); // should log: true
console.log(commutative(multBy3, subtract5, 10)); // should log: false
console.log(commutative(divBy4, subtract5, 48)); // should log: false
You are never calling your inner functions, and output1, output2, etc. are defined locally to those inner functions, not accessible in the scope of commutative. Also, you are overwriting the func1 and func2 parameters. Try this:
function commutative(func1, func2, value) {
return func2(func1(value)) === func1(func2(value));
}
// Test cases:
const multBy3 = n => n * 3;
const divBy4 = n => n / 4;
const subtract5 = n => n - 5;
console.log(commutative(multBy3, divBy4, 11)); // should log: true
console.log(commutative(multBy3, subtract5, 10)); // should log: false
console.log(commutative(divBy4, subtract5, 48)); // should log: false
Let's say function fib():
function fib(n) {
if (n < 2){
return n
}
return fib(n - 1) + fib (n - 2)
}
Now, let's say I want to display each step of this recursive function in a document.write, and progressively add the result of each iteration with a delay of 1000ms between steps. Can I do it without modifying the original function by perhaps having another function, passing this one as the argument, creating the output mechanism, and since it also returns a function, recursively add the delay?
No, but writing it as a generator instead would give you a useful interface to implement something like that
function*fib() {
for (let a = 1, b = 1, c = 0;; c = a+b, a = b, b = c) yield a;
}
const sleep = ms => new Promise(resolve => setTimeout(() => resolve(), ms));
const gen = fib();
// then, use it step by step
console.log(gen.next().value);
console.log(gen.next().value);
// OR with a delay inbetween
async function slowly() {
for (let v of gen) {
console.log(v);
await sleep(1000);
}
}
slowly();
Because your original function is synchronous, without modifying you cannot really call it as if it were asynchronous.
JavaScript allows you to overwrite a symbol like your function, fib. This allows you to redefine it whatever you just want. Maybe you could make it asynchronous with dynamically added behavior, I don't know, but that would be too complicated.
However, you said "I want to display each step of this recursive function ... with a delay of 1000 ms between steps". You can easily do this, because you can call fib synchronously, but print the results asynchronously! Example:
function fib(n) {
if (n < 2){
return n
}
return fib(n - 1) + fib (n - 2)
}
var queue = [];
var depth = 0;
var manageCall = function(fn){
return function() {
++depth;
let result = fn.apply(this, arguments);
--depth;
queue.push(" ".repeat(depth)+fn.name+"("+arguments[0]+") = "+result);
return result;
};
};
var fib = manageCall(fib);
fib(8);
var printDelayed = function() {
if (queue.length != 0) {
console.info(queue.pop());
setTimeout(printDelayed, 1000);
}
}
printDelayed();
fib is unchanged, but can follow how the recursion were executed.
Yeah, so ... You probably actually can do this, but you're gonna have to get really creative. This is extremely non-performant code, and likely would need some tweaks to actually function, but you could conceivably take this just a bit further to get what you're after.
What we're doing
So, we're going to be ripping out the guts of a defined function that's passed to our mangler function waitAndPrintFunc. That function will output the function as a string, and then use it to rebuild a Frankenstein function that's executed via eval.
PLEASE NOTE: Don't EVER use this in a production environment. This code is a living abomination just to prove that something like this could be done.
//global
let indexCounter = 0;
const waitAndPrintFunc = (func) => {
let wholeFunc = func.toString();
const funcName = wholeFunc.slice(8, wholeFunc.indexOf('(')).replace(' ', '');
let funcBody = wholeFunc.slice(wholeFunc.indexOf('{') + 1, wholeFunc.lastIndexOf('}'));
const returnIndex = funcBody.indexOf(`return ${funcName}`);
const meatyPart = funcBody.slice(returnIndex + 7);
wholeFunc = wholeFunc.split('');
funcBody = funcBody.split('');
funcBody.splice(
returnIndex,
funcBody.length - returnIndex,
`document.querySelector('.output').appendChild("step \${indexCounter++}: \${eval(meatyPart)}"); setTimeout(() => {${meatyPart}}, 1000);`
);
wholeFunc.splice(0, 9 + funcName.length, 'const MyRiggedFunction = ');
wholeFunc.splice(wholeFunc.indexOf(')') + 1, 0, ' => ');
wholeFunc.splice(wholeFunc.indexOf('{') + 1, wholeFunc.lastIndexOf('}'), ...funcBody);
console.log(wholeFunc.join(''))
eval(`${wholeFunc.join('')} ; MyRiggedFunction(1)`);
};
function fib(n) {
if (n < 2) {
return n;
}
return fib(n - 1) + fib(n - 2);
}
waitAndPrintFunc(fib);
I see that I can intercept a function call, if I intercept fib(n), it should be intercepted by its own recursive calls, right? https://bytes.babbel.com/en/articles/2014-09-09-javascript-function-call-interception.html I will try it
No, you can't do that.
You could definitely "tap" into fib in order to add some console.log:
// original function
function fib(n) {
if (n < 2){
return n
}
return fib(n - 1) + fib (n - 2)
}
// rebind the var `fib` to a wrapper to the original `fib`
var fib = ((orig) => (n) => {
console.log('tap:', n);
return orig(n)
}
)(fib);
console.log("result:", fib(7));
However if the prerequisite is that you cannot modify the original fib that means it's still working as synchronous function: adding the delay means that fib becomes asynchronous.
But the return value of fib itself, since it's recursive, is using an addition operator (fib(n - 1) + fib(n - 2)), and therefore is expecting an immediate value, not something delayed.
If the constraint is that you cannot modify the original fib but you can only tap into it, you can't add a timeout given the code you provided.
Said that, you can definitely tap into the function and schedule a console.log every 1000ms: however that means that the function is finished already to be executed, it's just the console.log for each step that is delayed.
And I don't think that's what you want.
Is there a way to achieve the code bellow with Javascript (ES6)?
If yes, how can I do it? I try this example, but it didn't work.
const funcA = (callback, arg1) => {
console.log("Print arg1: " + arg1); /* Print arg1: argument1 */
let x = 0;
x = callback(x, );
return x;
}
const funcB = (x, prefix) => {
console.log("Print prefix: " + prefix); /* Print prefix: PREFIX_ */
x = x + 1;
return x;
}
/* Exec function funcA */
let x = funcA(funcB( ,"PREFIX_"), "argument1");
console.log("Value of x: " + x); /* Value of x: 1 */
This is an approach with a defined placeholder as symbol to identify the parameter which is not yet set.
It features a this object which is bind to the calling function for further check and evaluation.
If the combined array of arguments object and this.arg has no more placeholder items, the function is called with parameters and return the function call.
If not, the new arguments array is bind to the function and returnd.
[?] denotes the placeholder symbol
funcB x prefix this.args args action
------- --- --------- ------------- -------------- ------------------------------
1. call [?] "PREFIX_" [?], "PREFIX_" return calling fn w/ bound args
2. call 0 [?] [?], "PREFIX_" 0, "PREFIX_" return fn call with args
3. call 0 "PREFIX_" return 1
(Of course it could be a bit shorter and delegated to another function, but it's a proof of concept.)
function funcA(callback, arg1) {
console.log('funcA', callback, arg1)
return callback(0, placeholder);
}
function funcB(x, prefix) {
var args = this && this.args || [],
temp = Array.from(arguments);
console.log('funcB', isPlaceholder(x) ? '[?]' : x, isPlaceholder(prefix) ? '[?]' : prefix);
// placeholder part
if (temp.some(isPlaceholder)) {
temp.forEach((a, i) => isPlaceholder(a) && i in args || (args[i] = a));
return args.some(isPlaceholder)
? funcB.bind({ args })
: funcB(...args);
}
// origin function body
return x + 1;
}
const
placeholder = Symbol('placeholder'),
isPlaceholder = v => v === placeholder;
console.log("Value of x: " + funcA(funcB(placeholder, "PREFIX_"), "argument1"));
Partial application is not yet possible in js. You need another arrow function that acts as a callback:
funcA(x => funcB(x ,"PREFIX_"), "argument1");
To call that you don't need that extra comma:
x = callback(x)
Somewhen this proposal might allow to write this:
funcA( funcB(?, "PREFIX_"), "argument1")
One approach would be to define a default parameter that is a function for the first parameter passed to funcA and use var to define x when funcA is called
const funcA = (callback, arg1) => {
console.log("Print arg1: " + arg1);
let x = 0;
x = callback(x, arg1);
return x;
}
const funcB = (x, prefix) => {
console.log("Print prefix: " + prefix);
x = x + 1;
return x;
}
/* Exec function funcA */
var x = funcA(x = () => funcB(x = 0 ,"PREFIX_"), "argument1");
console.log("Value of x: " + x);
Maybe there is already a solution, but I can't find it. I try to access different slots in a multi dimensional array dynamical but with the challenge of different depths. Basically, it looks like this:
var source = [];
source['lvl1'] = [];
source['lvl1']['lvl2a'] = [];
source['lvl1']['lvl2a']['lvl3'] = "ping";
source['lvl1']['lvl2b'] = "pong";
If the depth is fix, I could write code like this:
var path1 = ["lvl1","lvl2a","lvl3"];
var path2 = ["lvl1","lvl2b"];
console.log(source[path1[0]][path1[1]][path[2]]); // => ping
console.log(source[path2[0]][path2[1]]); // => pong
My problem is to write a code that works for both variants. This would work:
switch(path.length)
{
case 1:
console.log(source[path[0]]);
break;
case 2:
console.log(source[path[0]][path[1]]);
break;
case 3:
console.log(source[path[0]][path[1]][path[2]]);
break;
}
But this is neither efficient nor elegant. Has somebody another solution that works for example with some kind of loop?!?
Thanks
Thomas
This question has been answered quite some time ago, but I'd like to show a really simple one line solution using the array reducer:
const getRoute = (o, r) => r.split(".").reduce((c, s) => c[s], o);
let q = {a:{b:{c:{d:"hello world"}}}};
console.log(getRoute(q, 'a.b.c.d'));
This might help someone else :)
If you are sure that all the values in the array will exist, then you can simply use Array.prototype.reduce, like this
console.log(path1.reduce(function(result, currentKey) {
return result[currentKey];
}, source));
# ping
You can make it generic, like this
function getValueFromObject(object, path) {
return path.reduce(function(result, currentKey) {
return result[currentKey];
}, object);
}
And then invoke it like this
console.assert(getValueFromObject(source, path1) === "ping");
console.assert(getValueFromObject(source, path2) === "pong");
Note: You need to make sure that the source is a JavaScript object. What you have now is called an array.
var source = {}; # Note `{}`, not `[]`
You can loop and build up the value of source before logging it. Try this out:
var sourceValue = source[path[0]];
for (var i = 1; i < path.length; i++) {
sourceValue = sourceValue[path[i]];
}
console.log(sourceValue);
Here's a JSFiddle that demonstrates this approach works.
You can get a value from a path (tested code):
var getValue = function(path, context) {
if ('object' !== typeof context) {
throw new Error('The context must be an object; "' + typeof context + '" given instead.');
}
if ('string' !== typeof path) {
throw new Error('The path must be a string; "' + typeof context + '" given instead.');
}
var fields = path.split('.'),
getValueFromFields = function(fields, context) {
var field = fields.shift();
if (0 === fields.length) {
return context[field];
}
if ('object' !== typeof context[field]) {
throw new Error('The path "' + path + '" has no value.');
}
return getValueFromFields(fields, context[field]);
}
;
return getValueFromFields(fields, context);
}
var source = [];
source['lvl1'] = [];
source['lvl1']['lvl2a'] = [];
source['lvl1']['lvl2a']['lvl3'] = "ping";
source['lvl1']['lvl2b'] = "pong";
console.log(getValue('lvl1.lvl2a.lvl3', source)); // ping
console.log(getValue('lvl1.lvl2b', source)); // pong
In JavaScript, is it possible to insert a line into a function that already exists? I want to create a function that inserts a line at a specific position in a function:
function insertLine(theFunction, lineToInsert, positionToInsert){
//insert a line into the function after the specified line number
}
For example, would it be possible to programmatically insert the line checkParameterTypes(min, "string", max, "string"); before the first line of this function?
function getRandomInteger(min, max) {
return Math.floor(Math.random() * (max - min + 1)) + min;
}
If you want something to happen at the beginning of a function, you can use the following. You do have access to this and the arguments from your injected function. So it will still work for functions that require a specific context.
function inject(before, fn) {
return function(){
before.apply(this, arguments);
return fn.apply (this, arguments);
}
}
For example
function add(a, b) {
return a + b;
}
function concat(a, b) {
return a + b;
}
/**
* You can repeat index and type to check multiple arguments
*/
function createArgumentChecker(index, type /**index, type, ... */) {
var originalArgs = arguments;
return function() {
for (var i=0; i < originalArgs.length; i+=2) {
var index = originalArgs[i],
requestedType = originalArgs[i+1],
actualType = typeof arguments[index];
if (typeAtIndex != actualType) {
console.log("Invalid argument passed at index " + index +
". Expected type " + requestedType + "but it's " + actualType );
}
}
}
}
function logArguments() {
console.log(this, arguments);
}
// Inject an argument checker
add = inject(add, createArgumentChecker(0,"number", 1, "number"));
concat = inject (concat, createArgumentChecker(0, "string", 1, "string"));
// You can even do it multiple times, inject an argument logger;
add = inject(add, logArguments);
concat = inject(concat, logArguments);
JSfiddle
This can be handy when debugging websites that you can't modify the source code, I wouldn't use it do parameter checking unless you can strip it our for the production version.
Yes you can but using eval is always evil ;)
function insertInbetween (arr, value, index) {
var inserted, i, newarr = [];
for (i = 0; i < arr.length; i++) {
if(i == index && !inserted) {
newarr[i] = value;
inserted = true;
}
newarr.push(arr[i]);
}
return newarr;
}
function test (a, b) {
console.log(a,b);
}
var fstrarr = test.toString().split('\n');
eval(insertInbetween(fstrarr, "console.log('injected!');", 1).join('\n'));
Edit:
As mentioned in the comments to your question you'll loose scope by doing so.