Is the following attempt at the Hindley-Milner Type Signature for the compose function correct?
// compose :: (f -> [f]) -> (f -> f -> f) -> [f] -> f
const compose = (...fns) => fns.reduce((f,g) => (...args) => f(g(...args)));
No, that's not correct. Your compose
function takes an array of functions as input, and produces one (composed) function as the output, so that signature is clearly wrong. On the other hand, I don't think it's possible to write that function using the Hindley-Milner type system unless you make the assumption that all of the functions in fns
are unary functions of the same type: a -> a
(i.e. an array of endomorphisms).
compose :: [a -> a] -> (a -> a)
JavaScript is dynamically typed, so it actually allows each function in fns
to be a different type (JS doesn't require arrays to be homogeneous). This means that you may need to invent some new syntax in order to express the type of compose
as you have it. Here's how 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)
It uses this …
syntax in order to represent a variadic function. The right-most function in the parameter list is of type ((a, b, …, n) → o)
, meaning that it is a variadic function that returns an o
. This o
is then used as the input of the next function which is of type (o → p)
. This continues down the list of parameters until the left-most function is of type (y → z)
, where z
becomes the resultant type of calling the returned function: ((a, b, …, n) → z)
.