函数式编程:调用Curried函数

时间:2018-05-25 14:31:20

标签: javascript ecmascript-6 functional-programming currying

我正在以功能性编程风格实现游戏 Tic Tac Toe / Naughts and Crosses ,并且偶然发现了一个带有咖喱功能的障碍。

我在func(width, height, index)格式中有一个重复出现的函数模式,然后我希望将其归结,绑定widthheight并离开curriedFunc(index)

然而,当我的函数期望在编译时定义其中一个curried函数时会出现问题。

它们无法在编译时定义,因为它们需要用户输入,然后将值绑定到函数。

以下是我遇到的模式的一些示例代码。

// 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();

我能想到解决这个问题的唯一方法是将curried函数作为参数传递(在本例中为nextIndexInRowGivenWidth())。

但是我不认为这是理想的,就好像一个函数在运行时需要几个类似的curried函数一样,定义和curry这个函数很快变得难以处理。

理想的解决方案是,如果我可以以某种方式使值的动态绑定,假设我可以在getRowNum = getRowNumGivenWidth(width);之前放置声明main()。通过这种方式,我可以调用类似getRowNum(someInt)的内容来初始化getRowNum(),然后我可以在其他已经预期定义它的函数中使用它。

由于这是我的代码中反复出现的模式,我想知道是否有设计模式来实现这一点。

1 个答案:

答案 0 :(得分:2)

我认为你在寻找

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作为第一个curried参数,但将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));

  // ...
}