函数式编程:调用 Curried 函数
Functional Programming: Calling a Curried Function
我正在以函数式编程风格实现 Tic Tac Toe/Naughts and Crosses 游戏,并且偶然发现了一个障碍咖喱函数。
我有一个形式为 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();
我能想到的解决这个问题的唯一方法是将柯里化函数作为参数传递(在本例中传递给 nextIndexInRowGivenWidth()
)。
但是我认为这并不理想,因为好像一个函数在 运行 时需要一些类似的 curried 函数,定义和 curry 所述函数很快变得笨拙。
理想的解决方案是,如果我能以某种方式动态绑定值,假设我可以将声明 getRowNum = getRowNumGivenWidth(width);
放在 main()
之前。这样我就可以调用 getRowNum(someInt)
之类的东西来初始化 getRowNum()
然后我可以在其他已经期望它被定义的函数中使用它。
由于这是我代码中重复出现的模式,我想知道是否有设计模式可以实现这一点。
我想你正在寻找
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));
// ...
}
我正在以函数式编程风格实现 Tic Tac Toe/Naughts and Crosses 游戏,并且偶然发现了一个障碍咖喱函数。
我有一个形式为 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();
我能想到的解决这个问题的唯一方法是将柯里化函数作为参数传递(在本例中传递给 nextIndexInRowGivenWidth()
)。
但是我认为这并不理想,因为好像一个函数在 运行 时需要一些类似的 curried 函数,定义和 curry 所述函数很快变得笨拙。
理想的解决方案是,如果我能以某种方式动态绑定值,假设我可以将声明 getRowNum = getRowNumGivenWidth(width);
放在 main()
之前。这样我就可以调用 getRowNum(someInt)
之类的东西来初始化 getRowNum()
然后我可以在其他已经期望它被定义的函数中使用它。
由于这是我代码中重复出现的模式,我想知道是否有设计模式可以实现这一点。
我想你正在寻找
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));
// ...
}