我正在阅读一个名为Frisby教授的“函数式编程指南”的函数式编程教程,作者介绍了Hindley-Milner及其几个例子,其中之一是:
// reduce :: (b -> a -> b) -> b -> [a] -> b
var reduce = curry(function(f, x, xs) {
return xs.reduce(f, x);
});reduce的第一个参数是一个函数,它的类型签名是b -> a -> b,这正是我所不理解的部分。上面的代码是用js编写的,这意味着f应该使用两个参数并返回一个参数,如下所示:
function f(b, a) {
return b + a;
}因此,f的类型签名应该是(b, a) -> b而不是b -> a -> b,对吗?f不应该是一阶函数(由b -> a -> b隐含),至少在js中不应该。
所以我的问题是,这是教程的错误吗?如果是这样的话,用印地语-Milner表示(b, a) -> b的正确方法是什么?
发布于 2021-04-14 12:59:06
因为xs被注释为[a],所以我们可以期望它是一个常规的javascript数组。
因此,.reduce函数中的reduce调用可以假定为Array.prototype.reduce。
此数组方法不接受仓促还原函数。所以我会说:是的,类型注释是错误的。
去修复它
// reduce :: ((b, a) -> b) -> b -> [a] -> b,或Array.prototype.reduce的问题// reduce :: (b -> a -> b) -> b -> [a] -> b
var reduce = curry(function(f, x, xs) {
return xs.reduce((b, a) => f(b)(a), x);
// ^^^^^^^^^^^^^^^^^
});发布于 2021-04-14 08:27:26
我亲自学习了本教程,我认为通常假定函数是仓促的,所以f是b -> a -> b可能是违反直觉的,但也不一定是错误的。(把我说的每句话都听得一清二楚,我不是专家;)
然而,f本身在reduce签名中的括号为读者(至少对JavaScript阅读器)提供了一个重要的线索,即f是一个函数:
reduce :: (b -> a -> b) -> b -> [a] -> b
^^^^^^^^^^^^^ ^ ^^^ ^
1 2 3 4
1: f
2: reduction initial value
3: list to reduce
4: reduction result由于f可以被匆忙处理,所以不能保证您一次就能收到它的所有参数。当然,在这种特殊情况下(一个约简函数),大多数人都希望f同时应用于两个参数(累加值和值)。
函数签名只是一个“意向声明”(至少在JavaScript中是这样):
f采用两个参数。b类型。a类型(可以与b btw相同)。b类型。函数应该做什么没有定义。
如果b是一个数字,那么f的这个定义是很好的AFAIK:(尽管这是一个非常无用的还原函数)
const f = b => a => 42https://stackoverflow.com/questions/67084192
复制相似问题