【问题标题】:How to represent functions with multiple arguments in Hindley-Milner?如何在 Hindley-Milner 中表示具有多个参数的函数?
【发布时间】:2021-07-09 01:23:07
【问题描述】:

我正在阅读一个名为Professor Frisby's Mostly Adequate Guide to Functional Programming的函数式编程教程,作者对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 中不是。

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

【问题讨论】:

  • 元组是表示多个参数的正确方法。是的,这看起来像是教程中的一个错误/失误——在函数式编程中,函数通常是 curried,而在 javascript 中则不是。
  • 本教程使用的是lodash curry,所以我相信curried符号是指curry的“curriable”输出,即如果f(b, a) = b + a,那么curry(f)(b)(a) = b + a
  • @chiliNUT 但是f 不是(不应该)咖喱,只有reduce 是。

标签: javascript types functional-programming hindley-milner


【解决方案1】:

由于xs 被注释为[a],我们可以期望它是一个常规的javascript 数组。

因此,.reduce调用reduce函数可以假设为Array.prototype.reduce

此数组方法不采用 curried reducer 函数。所以我会说:是的,类型注释是错误的。

要修复它,要么

  1. 按照您的建议将类型注释更改为// reduce :: ((b, a) -> b) -> b -> [a] -> b,或者
  2. 更改实现以处理将柯里化函数传递给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);
//                 ^^^^^^^^^^^^^^^^^
});

【讨论】:

    【解决方案2】:

    我自己浏览了本教程,我认为通常假设函数是 curried 的,所以 fb -> a -> b 可能违反直觉,但不一定是错误的 AFAIK。 (把我说的每一句话都当回事;我不是专家;)

    但是,reduce 签名中 f 本身的括号为读者(至少对于 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 => 42
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-03-07
      • 2023-03-25
      • 1970-01-01
      • 2012-03-19
      • 2022-08-08
      相关资源
      最近更新 更多