Advent of Code 2017 Day 5 (part 1) in Functional Programming (FP)
Simple and pure

Regarding the comments the following is an example of a simple JS solution to the problem. Turns out that it is also a pure function.

// list is a copy of input, thus passing strings is inherently pure
function traverseJumpList(list) {
    list = list.split("\n");  // no need to parse the numbers as
                              // the ++ operator will coerce a string to
                              // a number for you..
    var jumps = 0, index = 0;
    // Assuming that an exit jump is also jumping to negative index
    while (index &gt;= 0 &amp;&amp; index &lt; list.length) {
        jumps += 1;
        index += list[index]++;
    }
    return jumps;
}
const solution = traverseJumpList(INPUT);


Recursion

This particular problem can not be solved via recursion without proper tail calls  because you can not know the max steps in advance. 

Memory

Even with tail calls on you are still fighting JS because you are not being memory aware. In the function jumper you create a new copy of the maze and then make the next jump via recursion.

This means for each jump you create a complete copy of the maze and hold it in memory until the end. So if you have a maze with 1024 items and it takes 2048 jumps to complete you will have 2097152 unique items. This is very wasteful by any standard.

You should release the previous maze before you make the next jump

  const jumper = input =&gt; {
    var currentMaze = input.maze;
    const currentPosition = input.position;
    const currentStepNumber = input.stepNumber;
    if (currentPosition &gt;= input.maze.length) {
       return currentStepNumber;  
    }
    const newOffset = input.maze[currentPosition] + 1;
    const maze = input.maze
     .slice(0, currentPosition)
     .concat(newOffset)
     .concat(input.maze.slice(currentPosition + 1));
    const position = currentPosition + input.maze[currentPosition];
    const stepNumber = currentStepNumber + 1;

    // clean up memory
    input = undefined;

    return jumper({maze, position, stepNumber});

  };


Indirect recursion.

An alternative to direct recursion is indirect recursion. This is done by calling the recuse function using a time event. The code is similar but you will need to provide the result as a function call.

This method gives unlimited recursion and frees up all incidental memory by releasing each recursive call's context from the heap before doing the next iteration. Also exiting to context idle makes GC more efficient.

Using your jumper function as an example.

  const jumper = input =&gt; {
    const currentMaze = input.maze;
    const currentPosition = input.position;
    const currentStepNumber = input.stepNumber;
    if (currentPosition &gt;= currentMaze.length) {
      // return currentStepNumber;  
      showAnswer(currentStepNumber);   // The result must be called in
      return;
    }
    const newOffset = currentMaze[currentPosition] + 1;
    const maze = currentMaze
     .slice(0, currentPosition)
     .concat(newOffset)
     .concat(currentMaze.slice(currentPosition + 1));
    const position = currentPosition + currentMaze[currentPosition];
    const stepNumber = currentStepNumber + 1;
    // call next step via timeout. This will not execute until after
    // this function has exited.
    setTimeout(() =&gt; jumper({maze, position, stepNumber}),0);

    // this function now exits before the next jump releasing the
    // original input object
  };


And the starting and answer functions

  jumper({maze: startMaze, position: 0, stepNumber: 0});
  const showAnswer = (result) =&gt; console.log(result);


Or you could have jumper return a promise on the first pass which resolves with the answer. I am not too sure if this fits the FP paradigm.