如何阅读 es6/javascript 中的功能组合?
How do I read functional composition in es6/javascript?
背景:
Composition is putting two functions together to form a third function where the output of one function is the input of the other.
无论我看多少次,我都在为如何阅读它而苦苦挣扎。特别是为什么 compose()
return => (a) =>
在本地范围内捕获 121.2121212
。此外,我还在为 final fn f(g(a))
在所有 values/fn 当前 w/o 变量的使用情况下的外观而苦恼。
问题:有没有人有快速阅读此类示例的技巧或图表;我如何在头脑中调试并遵循功能流程?
const compose = (f, g) => (a) => f(g(a)) // Definition
const floorAndToString = compose((val) => val.toString(), Math.floor) // Usage
floorAndToString(121.212121) // '121'
查看 function composition 的维基百科文章可能会有所帮助。但我认为你的问题与函数组合并不真正相关,而是与一般的箭头符号有关。
也许先看一个更简单的例子会有所帮助:
const addOne = (x) => x + 1
const addN = (n) => (x) => x + n
const addSeven = addN(7)
最后一行生成一个新函数,将输入加 7 (x) => x + 7
。您可以将箭头之间的参数元组视为在提供值时从左到右填充(并且右侧的变量绑定到这些值)。只要您不提供所有参数,您将获得一个新功能。
您还可以像这样提供所有参数:
addN(5)(3) // yields 8
请注意,addN 可以看作采用两个参数,但在单独的括号对中。定义中括号之间的箭头允许您省略右侧的参数并获得具有较少参数且左侧参数已经固定的函数。
让我们看一下 compose 的另一种定义:
const weirdCompose = (f, g, a) => f(g(a))
应该很清楚它是如何工作的,但问题是如果不立即用值 a
计算组合结果,就不能用它来组合两个函数。通过将参数分成两组,您可以 partially apply 函数并在第一步中仅提供 f
和 g
。
为了更好地理解这一点,我建议您也看看 currying
的概念
如 T.J 所述。 Crowder,它通常有助于将箭头函数重写为常规函数。所以函数:
const compose = (f, g) => (a) => f(g(a))
可以改写为:
function compose (f, g) {
return function (a) {
return f(g(a));
}
}
现在可能更清楚发生了什么。那么现在让我们重写其他部分:
const floorAndToString = compose((val) => val.toString(), Math.floor)
可以改写为:
function convertToString (val) { return val.toString() };
const floorAndToString = compose(convertToString, Math.floor);
现在可能更明显的是 compose
函数将 return 函数:
// remember that we pass `convertToString` as `f`
// and `Math.floor` as `g`:
function (a) {
return convertToString(Math.floor(a));
}
所以很明显,函数 floorAndToString
只是 return 是 convertToString(Math.floor(a))
的结果。捕获 121.2121212
的 compose
没有什么特别之处,因为它没有。相反,它创建了一个函数,其中 121.2121212
可以作为参数传递给 convertToString(Math.floor(a))
.
背景:
Composition is putting two functions together to form a third function where the output of one function is the input of the other.
无论我看多少次,我都在为如何阅读它而苦苦挣扎。特别是为什么 compose()
return => (a) =>
在本地范围内捕获 121.2121212
。此外,我还在为 final fn f(g(a))
在所有 values/fn 当前 w/o 变量的使用情况下的外观而苦恼。
问题:有没有人有快速阅读此类示例的技巧或图表;我如何在头脑中调试并遵循功能流程?
const compose = (f, g) => (a) => f(g(a)) // Definition
const floorAndToString = compose((val) => val.toString(), Math.floor) // Usage
floorAndToString(121.212121) // '121'
查看 function composition 的维基百科文章可能会有所帮助。但我认为你的问题与函数组合并不真正相关,而是与一般的箭头符号有关。
也许先看一个更简单的例子会有所帮助:
const addOne = (x) => x + 1
const addN = (n) => (x) => x + n
const addSeven = addN(7)
最后一行生成一个新函数,将输入加 7 (x) => x + 7
。您可以将箭头之间的参数元组视为在提供值时从左到右填充(并且右侧的变量绑定到这些值)。只要您不提供所有参数,您将获得一个新功能。
您还可以像这样提供所有参数:
addN(5)(3) // yields 8
请注意,addN 可以看作采用两个参数,但在单独的括号对中。定义中括号之间的箭头允许您省略右侧的参数并获得具有较少参数且左侧参数已经固定的函数。
让我们看一下 compose 的另一种定义:
const weirdCompose = (f, g, a) => f(g(a))
应该很清楚它是如何工作的,但问题是如果不立即用值 a
计算组合结果,就不能用它来组合两个函数。通过将参数分成两组,您可以 partially apply 函数并在第一步中仅提供 f
和 g
。
为了更好地理解这一点,我建议您也看看 currying
的概念如 T.J 所述。 Crowder,它通常有助于将箭头函数重写为常规函数。所以函数:
const compose = (f, g) => (a) => f(g(a))
可以改写为:
function compose (f, g) {
return function (a) {
return f(g(a));
}
}
现在可能更清楚发生了什么。那么现在让我们重写其他部分:
const floorAndToString = compose((val) => val.toString(), Math.floor)
可以改写为:
function convertToString (val) { return val.toString() };
const floorAndToString = compose(convertToString, Math.floor);
现在可能更明显的是 compose
函数将 return 函数:
// remember that we pass `convertToString` as `f`
// and `Math.floor` as `g`:
function (a) {
return convertToString(Math.floor(a));
}
所以很明显,函数 floorAndToString
只是 return 是 convertToString(Math.floor(a))
的结果。捕获 121.2121212
的 compose
没有什么特别之处,因为它没有。相反,它创建了一个函数,其中 121.2121212
可以作为参数传递给 convertToString(Math.floor(a))
.