I just want some feedback to improve readability and structure for this implementation of Hangman. The goal was to write it in a purely functional way. However, coming from an imperative background, I found it difficult to organize functional code.function Hangman(word, revealed = word.replace(/\w/g, '_'), errors = 0) {  const hasLost = errors > 5;  const hasWon = !hasLost && word === revealed;  const tryGuess = (letter, character, guess) =>    new RegExp(letter, i).test(character) ? character : '_';  const revealCharacter = (letter, character, guess) => /_/.test(guess) ?     tryGuess(letter, character, guess) : guess;  const revealLetters = (letter, [head, ...rest], [guess, ...guessed]) => {    const character = / /.test(head) ? ' ' : revealCharacter(letter, head, guess);    return rest.length ?      character + revealLetters(letter, rest, guessed) : character;  }  const getErrorCount = (guess, word, count) =>    new RegExp(guess, i).test(word) ? count : count + 1;  const getResult = () => hasLost ? 'You lose' : 'You win';  if (!hasWon && !hasLost) {    this.guess = letter => new Hangman(word,      revealLetters(letter, word, revealed),      getErrorCount(letter, word, errors));    console.log(revealed, errors);  } else {    console.log(getResult());  }}const game = new Hangman('Agile Development');game.guess('e').guess('a').guess('t').guess('z');UPDATE: Below is the revised edition of the code with the advised changes. The code base looks much cleaner and I decided to try to stick to only using primitives and functions. Having each function accomplish a single task increased the code size, but definitely improved the readability and maintainability of the code.function Hangman(text, revealed = null, errors = 0) {  { // constructor    if (revealed === null) {      return Hangman(text, revealMatch(/\s/g, text), 0);    }    if (isDone()) {      console.info(getGameStatus());    } else {     console.info(arguments);      return makeGuess;    }  }    function createMatchedCharacterList(matcher) {    return (revealed, actual, index) => {      if (matcher.test(actual)) {        revealed[index] = actual;      }      return revealed;    }  }    function revealMatch(matcher, text) {    return text.split('').reduce(createMatchedCharacterList(matcher), [])  }    function revealCharacter(guess) {    return Object.assign([], revealed, revealMatch(new RegExp(guess, 'i'), text));  }    function makeGuess(guess) {    return (hasCharacter(guess) && !hasGuessed(guess)) ?      Hangman(text, revealCharacter(guess), errors) :       Hangman(text, revealed, errors + 1);  }    function hasCharacter(character) {    return text.search(character) > -1;  }    function hasGuessed(guess) {    return revealed.join('').search(guess) > -1;  }    function hasLost() {    return errors > 5;  }    function hasWon() {    return text === revealed.join('');  }    function isDone() {    return hasLost() || hasWon();  }    function getGameStatus() {    return isDone() ? hasLost() ? 'You lose' : 'You win' : 'Incomplete';  }}console.log(Hangman('eatz')('e')('a')('t')('z'));
Hangman in stateless JavaScript
javascript;functional programming;hangman
Such a great question,hasLost and hasWon should be functionsYou should write functions with the keyword function, otherwise you get a mess of anonymous functions in stack-traces. The fat arrow syntax was only meant for inline functions.head is not a great variable name, I don't know what it is supposed to be from the nameOn the whole, the challenge in pure fp is to never assign, which you do a few times, read this for good measure: https://stackoverflow.com/a/33114654/7602I am not sure I like that the guess function creates a new Hangman object every single time, there has to be a cleaner approach.I found an interesting guide: https://drboolean.gitbooks.io/mostly-adequate-guide/ which states that this should be avoided.. Meanwhile, this is my this littered approach. It follows all my recommendations, and shows where I feel fat arrows have a place. I will try to rewrite again once I finish the guide ;)function Hangman(word, copy, mistakes){  //Initialize again, no assignments here ;)  if(!copy){    return Hangman(word, '_'.repeat(word.length), 0 );  }  //Non Exposed functions requiring context  const won = (() => {    return function won(){      return word == copy;                                 };                            })();  const lost = (() => {    return function lost(){      return mistakes > 5;    }  })();  const updateMistakes = (() => {    return function updateMistakes(oldCopy , newCopy){      return mistakes += oldCopy == newCopy ? 1 : 0;    }  })();  const applyGuess = (() => {    return function applyGuess(letter){      return copy  = word.split('').map( (c,i) => letter == c ?  c : copy[i] ).join('');    }  })();  //Exposed Functions  function guess(){    return function guess(letter){       if(!done()){        updateMistakes( copy , applyGuess(letter) );            }      this.display();      return this;    };  }  function display(){    return function display(){      console.log( won()? 'You won' : lost() ? 'You lost' : copy + ' ' + mistakes );    };  }  //Return object  return {    guess : guess(),    display: display(),      }  //Pure function?  function done(){    return won() || lost();  }  }const game = Hangman('Agile Development');game.guess('e').guess('a').guess('t').guess('z');Okay, 2nd version with far less this, many more clean functions:function Hangman(word, copy, mistakes){  //Initialize again, no assignments here ;)  if(!copy){    return Hangman(word, '_'.repeat(word.length), 0 );  }  //Exposed Functions  function guess(){    return function guess(letter){       if( !done( won(word,copy), lost(mistakes) ) ){        //An assignment, it was unavoidable I think        mistakes = updateMistakes( mistakes, copy , copy = applyGuess(word,copy,letter) );            }      display(word, copy, mistakes, letter );      return this;    };  }  //Return object, kind pointless now that there is only 1 function :/  return {    guess : guess()  }  //Not entirely pure function, not cacheable  function display(word, copy, mistakes, letter){    console.log( won(word,copy) ? 'You won' :                 lost(mistakes) ? 'You lost' :                 copy + ' ' + mistakes + ' You tried (' + letter + ')' );  }  //Pure functions!!  function applyGuess(word, copy, letter){    return word.split('').map( (c,i) => letter == c ?  c : copy[i] ).join('');  }  function updateMistakes(mistakes, oldCopy , newCopy){    return mistakes + (oldCopy == newCopy ? 1 : 0 );  }  function done(won, lost){    return won || lost;  }  function won(word, copy){    return word == copy;                               }     function lost(mistakes){      return mistakes > 5;  }}const game = Hangman('Agile Development');game.guess('e').guess('a').guess('t').guess('z');