Functional JavaScript:Compose 的 Hindley-Milner 类型签名是什么?

Functional JavaScript: What is the Hindley-Milner Type Signature of Compose?

以下对 compose 函数的 Hindley-Milner 类型签名的尝试是否正确?

// compose :: (f -> [f]) -> (f -> f -> f) -> [f] -> f
const compose = (...fns) => fns.reduce((f,g) => (...args) => f(g(...args)));

不,那是不正确的。您的 compose 函数将一组函数作为输入,并生成一个(组合)函数作为输出,因此签名显然是错误的。另一方面,我认为不可能使用 Hindley-Milner 类型系统编写该函数,除非您假设 fns 中的所有函数都是同一类型的一元函数:a -> a(即 endomorphisms 的数组)。

compose :: [a -> a] -> (a -> a)

JavaScript 是动态类型的,所以它实际上允许 fns 中的每个函数都是不同的类型(JS 不要求数组是同构的)。这意味着您可能需要 发明一些新语法 以表达您拥有的 compose 的类型。 Ramda (a functional utility library for JS) describes the type of R.compose:

((y → z), (x → y), …, (o → p), ((a, b, …, n) → o)) → ((a, b, …, n) → z)

它使用此 语法来表示可变参数函数。参数列表中最右边的函数是 ((a, b, …, n) → o) 类型,这意味着它是 returns 和 o 的可变参数函数。然后,此 o 用作下一个类型为 (o → p) 的函数的输入。这继续沿着参数列表向下直到最左边的函数是 (y → z) 类型,其中 z 成为调用返回函数的结果类型:((a, b, …, n) → z).

二元函数组合的类型用 Hindley–Milner 表示法更容易表达:

//    compose :: (b -> c) -> (a -> b) -> a -> c
const compose = f => g => x => f (g (x));