Today, I was going through the source code of Jane Street's Core_kernel
module and I came across the compose
function:
(* The typical use case for these functions is to pass in functional arguments
and get functions as a result. For this reason, we tell the compiler where
to insert breakpoints in the argument-passing scheme. *)
let compose f g = (); fun x -> f (g x)
I would have defined the compose
function as:
let compose f g x = f (g x)
The reason they give for defining compose
the way they did is “because compose
is a function which takes functions f
and g
as arguments and returns the function fun x -> f (g x)
as a result, they defined compose
the way they did to tell the compiler to insert a breakpoint after f
and g
but before x
in the argument-passing scheme.”
So I have two questions:
- Why do we need breakpoints in the argument-passing scheme?
- What difference would it make if we defined
compose
the normal way?
Coming from Haskell, this convention doesn't make any sense to me.
map f = go where { go [] = []; go (a : as) = f a : go as }
. – Froemmingmap
is recursive. Hence,go as
is more efficient thanmap f as
. I don't see how the same concept would apply tocompose
considering that it is not recursive. – Suhailf x = \y -> ...
andf x y = ...
despite them being semantically identical. – Froemming