The stackless model so far has been built on a generic and comprehensible building block called a YIELDER. I thought I'd walk through it a little.
To understand YIELDER, first look at GENERATOR
I think a generator is pretty easy to understand. It is like a function, but instead of RETURN it has something called YIELD. Each time YIELD is called the generator gives back the result but is left in a suspended state, and the next call to the generator will pick up right after the YIELD:
counter: generator [ let n: 0 while [true] [ n: n + 1 yield n ] ] >> counter == 1 >> counter == 2
Generators are building blocks, meant to be used with functions
Generators don't take parameters. So if you want to parameterize them, you should combine them with a function. Imagine you wanted to be able to specify a bump amount for your counter:
make-counter: func [bump] [ return generator [ let n: 0 while [true] [yield n: n + 1] ] ] >> counter: make-counter 5 >> counter == 1 >> counter == 6 >> counter == 11
But functions aren't limited to being just "generator makers"...
For instance: functions can be generator wrappers, that actually delegate to the generator...or perhaps even destroy it and make new ones. Consider making a resettable counter, as @giuliolunati has in his GENERATE usermode generator:
counter: func [/reset <static> n (0) gen (null)] [ if reset [n: 0 | return] return reeval gen: default [ generator [ while [true] [yield n: n + 1] ] ] ] >> counter == 1 >> counter == 2 >> counter/reset >> counter == 1 >> counter == 2
This gives a lot of flexibility in the design of generator interfaces. Considering the above example alone: what if you are in a situation where you think the counter/reset should have returned 1 instead of being a separate step that had no return result? Or maybe you think it should have returned what the last generator value was.
By making generators a "simplistic" building block, you're in control of these interface choices.
The YIELDER hybridizes with functions for efficiency
I said that generators don't have parameters or a function spec, but that is because they are a specialization of a version that does have a spec... called a YIELDER.
weird-print: yielder [x] [ while [true] [ print ["Odd print:" x] yield void print ["Even print:" x] yield void ] ] >> weird-print "Hello" Odd print: Hello >> weird-print "Weird" Even print: Weird >> weird-print "World" Odd print: World
This isn't anything you couldn't have achieved with a function that wrapped a generator, that held that generator statically and then sub-dispatched to it. It's just cleaner and more efficient. (Since GENERATOR is implemented as
yielder  [...generator body...] it's kind of like the DOES analogue to FUNC.)
But this kind of gives you a sense of the parts box you have for building relatively efficient generator-type things.