组合不纯函数
Composing impure functions
假设我有以下不纯函数:
// Mounts a foo instance into the given dom node
// (this is an implementation detail of the Foo library),
// then returns the foo instance.
const createFoo = (FooConstructor, domNode, options) => {
return new FooConstructor(domNode, options);
};
const outlineFoo = foo => {
foo.getCanvas().outline = true;
return foo;
}
如果我想使用 R.compose
创建 Foo 实例并突出显示它,我可以编写一个函数来执行以下操作:
const createFooWithHighlights = (FooConstructor, domNode, options) => {
return R.compose(
outlineFoo,
createFoo
)(FooConstructor, domNode, options)
}
如果我想使用命令式编程来完成同样的事情,我会这样做:
const createFooWithHighlights = (FooConstructor, domNode, options) => {
const foo = createFoo(FooConstructor, domNode, options);
outlineFoo(foo);
return foo;
}
无论我们选择哪个,它都会被相同地调用:
const highlightedFooInDOM = createFooWithHighlights(Foo, document.body, {})
既然所有这些功能都会产生副作用,我应该避免使用 R.compose
吗?是否有关于纯度和功能组成的规则?
首先,一个简化。你应该能够更简单地写 createFooWithHighlights
为:
const createFooWithHighlights = R.compose(outlineFoo, createFoo);
现在开始真正的问题:
Since all of these functions produce side effects, should I avoid using R.compose
? Are there rules governing purity and function composition?
我会说不是。函数式编程当然是关于减少副作用,将它们分流到程序的边缘,甚至可能将它们封装在模式和结构中(请参阅对 IO Monad 的评论,这当然是个好建议,但可能为时过早。)
但这与消除副作用无关。一个绝对没有副作用的程序只能计算一些硬编码输入的结果......然后懒得与你分享。
Ramda(免责声明:我是作者之一)严格避免副作用。但这是应该的。它是一个功能实用程序库;你不是那些决定你的程序如何与世界其他地方互动的人之一。或者至少我们 Ramda 团队没有。所以 Ramda 函数是纯函数。此外,Ramda 旨在让您在实用的情况下以纯函数的方式轻松工作。
但这并不意味着它的函数应该只能用于创建其他纯函数。当你需要创建副作用时,引入 Ramda 的工具完全没有问题,尤其是像功能组合这样重要的工具。
所以你想做的似乎完全符合 Ramda 的正常使用。
假设我有以下不纯函数:
// Mounts a foo instance into the given dom node
// (this is an implementation detail of the Foo library),
// then returns the foo instance.
const createFoo = (FooConstructor, domNode, options) => {
return new FooConstructor(domNode, options);
};
const outlineFoo = foo => {
foo.getCanvas().outline = true;
return foo;
}
如果我想使用 R.compose
创建 Foo 实例并突出显示它,我可以编写一个函数来执行以下操作:
const createFooWithHighlights = (FooConstructor, domNode, options) => {
return R.compose(
outlineFoo,
createFoo
)(FooConstructor, domNode, options)
}
如果我想使用命令式编程来完成同样的事情,我会这样做:
const createFooWithHighlights = (FooConstructor, domNode, options) => {
const foo = createFoo(FooConstructor, domNode, options);
outlineFoo(foo);
return foo;
}
无论我们选择哪个,它都会被相同地调用:
const highlightedFooInDOM = createFooWithHighlights(Foo, document.body, {})
既然所有这些功能都会产生副作用,我应该避免使用 R.compose
吗?是否有关于纯度和功能组成的规则?
首先,一个简化。你应该能够更简单地写 createFooWithHighlights
为:
const createFooWithHighlights = R.compose(outlineFoo, createFoo);
现在开始真正的问题:
Since all of these functions produce side effects, should I avoid using
R.compose
? Are there rules governing purity and function composition?
我会说不是。函数式编程当然是关于减少副作用,将它们分流到程序的边缘,甚至可能将它们封装在模式和结构中(请参阅对 IO Monad 的评论,这当然是个好建议,但可能为时过早。)
但这与消除副作用无关。一个绝对没有副作用的程序只能计算一些硬编码输入的结果......然后懒得与你分享。
Ramda(免责声明:我是作者之一)严格避免副作用。但这是应该的。它是一个功能实用程序库;你不是那些决定你的程序如何与世界其他地方互动的人之一。或者至少我们 Ramda 团队没有。所以 Ramda 函数是纯函数。此外,Ramda 旨在让您在实用的情况下以纯函数的方式轻松工作。
但这并不意味着它的函数应该只能用于创建其他纯函数。当你需要创建副作用时,引入 Ramda 的工具完全没有问题,尤其是像功能组合这样重要的工具。
所以你想做的似乎完全符合 Ramda 的正常使用。