Функциональное программирование: вызов функции Curried - PullRequest
0 голосов
/ 25 мая 2018

Я реализую игру Tic Tac Toe / Naughts and Crosses в стиле функционального программирования и наткнулся на препятствие с карри функциями.

Iесть повторяющийся шаблон функций в виде func(width, height, index), который я затем хочу карри, связывая width и height и оставляя curriedFunc(index).

Однако проблема возникает, когда у меня есть функции, которые ожидают одногоиз этих карри функций должны быть определены во время компиляции.

Они не могут быть определены во время компиляции, потому что они нуждаются в вводе от пользователя, чтобы затем связать значения с функцией.

Ниже приведеноПример кода, с которым я столкнулся.

// Board indexes:
//  0 | 1 | 2
// ---+---+---
//  3 | 4 | 5
// ---+---+---
//  6 | 7 | 8

const getRowNumGivenWidth = w => i => Math.floor(i/w);

// I want to be able to declare nextIndexInRowGivenWidth() here, outside of main()
// but getRowNum() needs to be defined beforehand


const main = () => {

  // User input:
  const width = 3;

  // ...


  const getRowNum = getRowNumGivenWidth(width);

  const nextIndexInRowGivenWidth = width => currentIndex => {
    const rowNum = getRowNum(currentIndex);
    const nextIndex = currentIndex + 1;

    if (getRowNum(nextIndex) != rowNum)
      result = nextIndex - width;
    else
      result = nextIndex;

    return result;
  };


  const nextIndexInRow = nextIndexInRowGivenWidth(width);

  const board = [0, 1, 2, 3, 4, 5, 6, 7, 8];

  board.map(x => console.log(x, " -> ", nextIndexInRow(x)));

  // ...

}

main();

Единственный способ решить эту проблему - передать функцию curry в качестве аргумента (nextIndexInRowGivenWidth() в этом примере).

Однако я не думаю, что это идеально, так как если для функции требуется несколько аналогично каррированных функций во время выполнения, она быстро становится громоздкой для определения и каррирования указанной функции.

Идеальным решением было бы, если бы я мог каким-то образом сделать привязку значений динамическим, предположим, что я мог бы поместить объявление getRowNum = getRowNumGivenWidth(width); перед main().Таким образом, я мог бы вызвать что-то вроде getRowNum(someInt) для инициализации getRowNum(), который я мог бы затем использовать в других функциях, которые уже ожидали его определения.

Поскольку это повторяющийся шаблон в моем коде, я былинтересно, есть ли шаблон дизайна для этого.

1 Ответ

0 голосов
/ 25 мая 2018

Я думаю, что вы ищете

const getRowNumGivenWidth = w => i => Math.floor(i/w);

const nextIndexInRowGivenWidth = width => {
  const getRowNum = getRowNumGivenWidth(width);
//^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  return currentIndex => {
    const nextIndex = currentIndex + 1;

    if (getRowNum(nextIndex) != getRowNum(currentIndex))
      return nextIndex - width;
    else
      return nextIndex;
  };
};

const main = () => {
  // User input:
  const width = 3;
  const nextIndexInRow = nextIndexInRowGivenWidth(width);

  // ...
}

В качестве альтернативы, вы можете определить, что функция nextIndexInRowGiven… не с width в качестве первого параметра карри, но с самим getRowNum в качестве параметра:

const getRowNumGivenWidth = w => i => Math.floor(i/w);

const nextIndexInRowGivenRowNumGetter = getRowNum => currentIndex => {
  const nextIndex = currentIndex + 1;

  if (getRowNum(nextIndex) != getRowNum(currentIndex))
    return nextIndex - width;
  else
    return nextIndex;
};

const main = () => {
  // User input:
  const width = 3;
  const nextIndexInRow = nextIndexInRowGivenRowNumGetter(getRowNumGivenWidth(width));

  // ...
}
...