Monday, January 9, 2017

memoize(f) or, Fib.apply(n)

a Matryoshka doll dance

Fib.apply( ):
Fib.apply( ):
Fib.apply( ):

function memoize(f, args) {

  // Provide default values for any missing arguments

  if (args === undefined || args  === null) {
    args = {};
  }
  if (args.map === undefined || args.map === null) {
    args.map = {};
  }
  if (args.getKey === undefined || args.getKey === null) {
    args.getKey = function() {
      return arguments.length > 0 ? arguments[0] : 0;
    };
  }

  // Set the values of the utilities map and getKey

  const map = args.map;
  const getKey = args.getKey;

  // Verify the types of the function argument and the utilities

  const fType = (typeof f).toLowerCase();
  const mapType = (typeof map).toLowerCase();
  const getKeyType = (typeof getKey).toLowerCase();

  if (fType !== 'function') {
    throw Error('f is not a function');
  }
  if (mapType !== 'object' && mapType !== 'function') {
    throw Error('invalid map type');
  }
  if (getKeyType !== 'function') {
    throw Error('getKey is not a function');
  }

  // Return the memoized version of the function f

  return function() {
    const key = getKey.apply(this, arguments);
    if (!map.hasOwnProperty(key)) {
      map[key] = f.apply(f, arguments);
    }
    return map[key];
  }
}

const Fib = new function() {
  const fib = memoize(function(i) { 
    if (i === 1) {
      return 1;
    }
    else if (i > 0) {
      return fib(i-2) + fib(i-1);
    }
    else if (i < 0) {
      return fib(i+2) - fib(i+1);
    }
    else {
      return 0;
    }
  });
  this.apply = function(n) {
    const i = parseInt(n);
    return i === parseFloat(n) ? fib(i) : undefined;
  };
};

See also