Summary: you can't do this, but that function isn't useful in F#; just use the |>
operator instead.
Longer version: there is no way to annotate the bind
function that you've described in a way that will satisfy the F# compiler. When I paste let rec bind x f = f x |> bind
into F# Interactive, it gives me the following error:
error FS0001: Type mismatch. Expecting a
''a -> 'b'
but given a
''a -> ('a -> 'a) -> 'b'
The types ''b' and '('a -> 'a) -> 'b' cannot be unified.
If we rearrange the definition a little to look like let rec bind x f = bind (f x)
instead, we get a slightly simplified type error:
error FS0001: Type mismatch. Expecting a
''a'
but given a
''b -> 'a'
The types ''a' and ''b -> 'a' cannot be unified.
With a bit of type hinting (let bind (x : 'x) (f : 'f) = ...
), we get the error that the types 'a
and 'f -> 'a
cannot be unified, so it becomes clear what's going on. 'a
is the return type of bind
(in the absence of any names for generic types, F# assigns them starting with 'a
). Now let's look at why this type error is happening.
It looks like tou already know about partial application: any two-argument function, when given a single argument, returns a function that waits for its second argument before evaluating the function body. In other words, let f a b = ...
in F# is equivalent to the Javascript const f = a => b => ...
. Here, the bind
function, when given a single argument x
, returns a function that waits for an f
before evaluating the body of bind
. That means that when bind
is passed a single parameter, its return type is 'f -> 'a
(where 'a
is, as we said, the name that the F# compiler has arbitrarily assigned to the result of bind
).
However, here's where the type conflict comes in: the value bind (f x)
, which has the value of 'f -> 'a
as we've already said, is also the result of your bind
function. That means that it should have the type 'a
. So the F# compiler would need to compile that function in such a way that the type 'a
is the same type as 'f -> 'a
. If that were possible, then in type algebra 'a = 'f -> 'a
, and you could then expand the 'a
in the right-hand side of that equation to be 'f -> 'a
, so that the equation becomes 'a = 'f -> ('f -> 'a)
. You could now expand the 'a
again, getting 'a = 'f -> ('f -> ('f -> 'a))
. And so on infinitely. The F# compiler does not allow infinitely-expanding types, so this is not allowed.
But as I already pointed out (and Tomas Petricek explained), you don't actually need this bind
function in F#. All it is is a way to hook functions into a pipeline, where the output of one function will be passed into the input of the next one (as your Javascript example demonstrates). And in F#, the idiomatic way to do this is with the "pipeline" operator. Instead of bind "input value" f1 f2 f3
(where f1, f2 and f3 are three functions of appropriate type), in F# you'd simply write:
"input value"
|> f1
|> f2
|> f3
This is normal, idiomatic F# and will be understood by pretty much anyone, even those who aren't particularly familiar with functional programming. So there's no need for this bind
function in F#.