> A Rama operation does not return a value to its caller. It emits values to its continuation. This is a critical distinction, as part of what makes Rama operations more general than functions is how they can emit multiple times, not emit at all, or emit asynchronously.
What is the best introductory post to Rama right now?<p>I would like to skip the marketing and understand how it compares to a wiring together Kafka, Spark, MySQL, etc.
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.<p>E.g.<p><pre><code> (?<-
(ops/explode [1 2 3 4] :> *v)
(println "Val:" *v))
</code></pre>
Is (I believe) the equivalent of Python's<p><pre><code> for element in [1, 2, 3, 4]:
print(element)</code></pre>
The whole thing about distinguishing functions that yield once from all other functions is pretty clever. Reminds me of how in Icon a `return` is a C-like return that unwinds the stack while `suspend` is more like calling a continuation with the yielded value. In the old Icon-to-C compiler that's exactly how `return` and `suspend` worked. But Icon does not analyze function ("procedure") bodies to see if they only return, so the `return`-unwinds optimization is a run-time one. Whereas Rama does a compile-time optimization, which makes a lot of sense.
Could I politely suggest more Clojure-like naming? `deframaop -> defop`. You can always `(require 'com.rpl.rama :as rama)` and invoke with `(rama/defop ...)` for the desired level of clarity and improved readability.
I feel like CPS is one of those tar pits smart developers fall into. It’s just a fundamentally unfriendly API, like mutexes.
We saw this with node as well: eventually the language designers just sighed and added promises.<p>You’re better off with an asynchronous result stream, which is equivalent in power but much easier to reason about. C#’s got IAsyncEnumerable, I know that Rust is working on designing something similar. Even then, it can be hard to analyse the behaviour of multiple levels of asynchronous streams and passing pieces of information from the top level to the bottom level like a tag is a pain in the neck.
Just hours (a day?) earlier there was this very interesting -and IMO relevant here- HN post:<p><pre><code> Can logic programming be liberated
from predicates and backtracking?
[pdf] (uni-kiel.de)
https://news.ycombinator.com/item?id=41816545
</code></pre>
That deals with backtracking, which is often implemented with continuations, as in TFA.
I don’t want to be a party pooper, but from my very cursory look at the page, I don’t think this will go much farther than a very small community. I feel like you’re adding a lot of complexity compared to normal backhand/frontend/websetvices Scenario that everybody already understand.
I’ve always thought that CPS is a good barometer for finding out whether a developer is talented or whether they THINK they’re talented enough to design and/or implement these kinds of compiler components. This kind of thing but definitely CPS in particular is so much trickier to nail down than it initially seems if you’ve written a compiler before. Up there in difficulty with automatic parallelization and loop transforming. I tried to write a very small POC lisp once with an idea to have all vectors of known sizes get map’d in parallel and I never could nail it down.<p>Kudos to all involved. Clojure is such a mind bending tool. God only knows what it takes these people to maintain the guts of it all.