Является ли следующая попытка подписи типа Hindley-Milner для функции компоновки правильной?
// compose :: (f -> [f]) -> (f -> f -> f) -> [f] -> f
const compose = (...fns) => fns.reduce((f,g) => (...args) => f(g(...args)));
Нет, это не правильно. Ваша функция compose
принимает в качестве входных данных множество функций и создает одну (сложенную) функцию в качестве вывода, так что подпись явно неверна. С другой стороны, я не думаю, что можно написать эту функцию с использованием системы типа Хиндли-Милнера, если вы не сделаете предположение, что все функции из fns
являются унарными функциями одного и того же типа: a → a
(т.е. массив эндоморфизмов).
compose :: [a -> a] -> (a -> a)
JavaScript динамически типизирован, поэтому он фактически позволяет каждой функции в fns
быть другим типом (JS не требует однородности массивов). Это означает, что вам может понадобиться изобрести какой-то новый синтаксис, чтобы выразить тип compose
как у вас есть. Здесь, как Ramda (функциональная библиотека утилиты для JS) описывает тип R.compose
:
((y → z), (x → y), …, (o → p), ((a, b, …, n) → o)) → ((a, b, …, n) → z)
Он использует этот …
синтаксис для представления вариационной функции. Самая правая функция в списке параметров имеет тип ((a, b, …, n) → o)
, что означает, что это вариационная функция, которая возвращает o
. Затем этот o
используется как вход следующей функции, которая имеет тип (o → p)
. Это продолжается до списка параметров до тех пор, пока левая функция не будет ((a, b, …, n) → z)
тип (y → z)
, где z
становится результирующим типом вызова возвращаемой функции: ((a, b, …, n) → z)
.