我正在以功能性编程风格实现游戏 Tic Tac Toe / Naughts and Crosses ,并且偶然发现了一个带有咖喱功能的障碍。
我在func(width, height, index)
格式中有一个重复出现的函数模式,然后我希望将其归结,绑定width
和height
并离开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()
,然后我可以在其他已经预期定义它的函数中使用它。
由于这是我的代码中反复出现的模式,我想知道是否有设计模式来实现这一点。
答案 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));
// ...
}