How to serialize javascript italic arrow functions?

const makeIncrementer = s=>a=>a+s
makeIncrementer(10).toString()    // Prints 'a=>a+s'

which would make proper serialization impossible (I would expect something like that a=>a+10). Is there any way to do this right?

+4
source share
3 answers

By combining the ideas from the two answers so far, I managed to create something that works (although I have not tested it completely):

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 arguments. It also supports higher order functions. You still need to be able to wrap the original function in serializable do , applying it to any arguments. Thanks to @MattWay and @ftor for their valuable contributions!

0
source

. , /s -, . , , . - , :

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
Hide result

: , , , / , args, . , , !. find/replace, . , . , incrementer, , .

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
Hide result
+3

/ , . , :

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
);
Hide result

Symbol, .

As mentioned in the code, you still cannot serialize higher-order functions.

+1
source

Source: https://habr.com/ru/post/1695997/


All Articles