zlacker

[return to "Rama on Clojure's terms, and the magic of continuation-passing style"]
1. robert+uo1[view] [source] 2024-10-14 16:19:19
>>nathan+(OP)
This article is written for people who know Clojure, or at least the examples are. It might be nice to see the examples written in a non-LISP as well.

E.g.

  (?<-
    (ops/explode [1 2 3 4] :> *v)
      (println "Val:" *v))
Is (I believe) the equivalent of Python's

  for element in [1, 2, 3, 4]:
    print(element)
◧◩
2. nathan+uI1[view] [source] 2024-10-14 18:13:21
>>robert+uo1
That Python code has the same effect, but the equivalent Python in CPS would be:

  def explode(args, cont):
    for e in args:
       cont(e)
  
  (explode [1, 2, 3, 4], print)
◧◩◪
3. gpdere+In3[view] [source] 2024-10-15 09:17:52
>>nathan+uI1
That's not in CPS form as cont returns into explode. Even if we treat the for loop in explode as an implementation detail, cont should take the next continuation as a parameter.
◧◩◪◨
4. crypto+R64[view] [source] 2024-10-15 15:09:28
>>gpdere+In3
From TFA:

> For every invoke, Rama determines if it’s executing a deframaop or a deframafn . If it’s a deframafn , then it invokes it just like how functions are invoked in Clojure by unrolling the stack frame with the return value. [...]

So I think GP's Python example matches quite well with what Rama does in the Rama equivalent from TFA.

Functions in Rama do return like normal functions in Clojure. It's Rama "ops" that call the continuation, but "ops" clearly _can_ return back to the caller, as that's how the whole generator aspect of Rama works -- it couldn't be any other way. So `println` is a function and it returns to its caller.

This is very different from a Scheme that compiles to CPS such that every return is a continuation call. The point is that in such a Scheme you end up with all activation frames being on the heap and thus needing garbage collection. This is why delimited continuations were invented: Scheme-style call/cc continuations are just too expensive!

But there is another optimization one can do: some returns can just unwind, while others can call a continuation. This is the optimization that Rama is going for near as I can see. It's a lot like Icon's `return`, which unwinds (in the Icon-to-C compiler anyways) and Icon's `suspend`, which calls the current continuation (again, in the Icon-to-C compiler case). This way you can return when you're not generating results -- when you're returning the last value, or when pruning (in Icon that's failure, which also unwinds, like `return`).

[go to top]