Remember the answers

Write a function that makes another function remember its results.

What to build

memoize(fn), which returns a version of fn that only does the work the first time it sees a value.

Requirements

  • The starter counts how many times square really runs.
  • Complete memoize(fn) so that the function it returns stores each result, and returns the stored result when the same argument appears again.
  • Do not change the rest of the program.

Input

Several lines, each a whole number.

Output

One line for each number, and then the total number of real calls. The starter prints these for you.

Constraints

There are from 1 to 100 numbers, from -1000 to 1000.

Example

Input:

2
3
2

Output:

2 -> 4 (computed)
3 -> 9 (computed)
2 -> 4 (cached)
calls: 2

Why it works

The Map lives in memoize's scope, so it survives between calls and nothing else can reach it. Checking with has matters because a stored answer can be 0, which is falsy.

Examples

Example 1 · Input
2
3
2
Expected output
2 -> 4 (computed)
3 -> 9 (computed)
2 -> 4 (cached)
calls: 2
Example 2 · Input
5
5
5
Expected output
5 -> 25 (computed)
5 -> 25 (cached)
5 -> 25 (cached)
calls: 1

Hints

Hint 1

memoize creates one Map, and returns a function that can see it.

Hint 2

Use cache.has(x), not cache.get(x), because a stored result can be 0.

Hint 3

If the Map has no answer yet, call fn(x), store the result and return it.

Solution

Show one correct solution (try it yourself first)
let calls = 0;

function square(x) {
  calls++;
  return x * x;
}

function memoize(fn) {
  const cache = new Map();
  return (x) => {
    if (!cache.has(x)) {
      cache.set(x, fn(x));
    }
    return cache.get(x);
  };
}

const fast = memoize(square);
let line = prompt();
while (line !== null) {
  const x = Number(line);
  const before = calls;
  const result = fast(x);
  console.log(`${x} -> ${result} ${calls > before ? "(computed)" : "(cached)"}`);
  line = prompt();
}
console.log(`calls: ${calls}`);

Lesson: Scope and closures →