首页 > 解决方案 > 如何在 Hindley-Milner 中表示具有多个参数的函数?

问题描述

我正在阅读一个名为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 中不应该。

所以我的问题是,这是教程的错误吗?(b, a) -> b如果是这样,在 Hindley-Milner中表示的正确方法是什么?

标签: javascripttypesfunctional-programminghindley-milner

解决方案


我自己浏览了本教程,我认为通常假设函数是咖喱的,所以f存在b -> a -> b可能是违反直觉的,但不一定是错误的 AFAIK。(把我说的每一句话都拿在手里;我不是专家;)

然而,签名中的括号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 can be curried,因此无法保证您会一次性收到所有参数。当然,在这种特殊情况下(一个归约函数),大多数人会期望它f同时应用于两个参数(一个累积值和一个值)。

函数签名仅仅是“意图声明”(至少在 JavaScript 中):

  • f有两个参数。
  • 第一个参数必须是b类型。
  • 第二个参数必须是一个a类型(可以b与btw相同)。
  • 返回值类型是一个b类型。

该函数应该做什么没有定义。

如果b是一个数字,那么这个定义f很好 AFAIK:(尽管那将是一个非常无用的归约函数)

const f = b => a => 42

推荐阅读