However, I am wondering if you can express one in another? All CPS-style languages I have seen have an explicit FIX
construct to define recursion.
FIX
? If so, do you know the proof of such thing?I would expect a Y-combinator-like CPS function CPSY
to work as this:
If I define a Y-ready CPS function, such as:
function Yready(this, return) =
return (lambda <args> . <body using 'this' as recursion>);
I would then put it into CPSY
to produce a function that recurses into itself:
function CPSY(F, return) = ?????
CPSY(Yready,
lambda rec . <body where 'rec' names 'lambda <args>' from above, but with the loop closed>
)
The CPSY
should be a plain continuation-passing style function without itself relying on any recursion. Y-combinator can be defined in such a way in plain lambda calculus without built-in recursion. Can it exist, in some form, in CPS as well?
To reiterate for clarification: I am looking for a combinator-like function CPSY
that:
CPSY
)Let's first derive CPS-Y for normal-order evaluation in lambda calculus, and then convert it to applicative-order.
Wikipedia page defines fixed-point combinator Y by the following equation:
Y f = f (Y f)
In CPS form, this equation would look rather like this:
Y f k = Y f (λh. f h k)
Now, consider the following non-CPS normal-order definition of Y:
Y f = (λg. g g) (λg. f (g g))
Transform it to CPS:
Y f k = (λg. g g k) (λg.λk. g g (λh. f h k))
Now, beta-reduce this definition a couple of times to check that it indeed satisfies the “CPS fixed-point” condition above:
Y f k = (λg. g g k) (λg.λk. g g (λh. f h k))
= (λg.λk. g g (λh. f h k)) (λg.λk. g g (λh. f h k)) k
= (λg.λk. g g (λh. f h k)) (λg.λk. g g (λh. f h k)) (λh. f h k)
= Y f (λh. f h k)
Voila!
Now, for applicative-order evaluation, of course, we would need to change this a bit. The reasoning here is the same as in non-CPS case: we need to “thunk” the recursive (g g k)
call and proceed only when called for the next time:
Y f k = (λg. g g k) (λg.λk. f (λx.λk. g g (λF. F x k)) k)
Here's a direct translation into Racket:
(define (Y f k)
((λ (g) (g g k))
(λ (g k) (f (λ (x k) (g g (λ (F) (F x k)))) k))))
We can check that it actually works — for example, here's the recursive triangular number calculation in CPS (except for arithmetic operations, for simplicity):
(Y (λ (sum k) (k (λ (n k) (if (< n 1)
(k 0)
(sum (- n 1) (λ (s) (k (+ s n))))))))
(λ (sum) (sum 9 print)))
;=> 45
I believe this answers the question.