Hi, I'm trying to understand this. The example of a generator which you give below counts upwards, but I don't see how the value of n is passed out of the generator. Could you give another example of a generator which does pass out the values, along with a usage case which prints out the values returned by the generator? Best regards, Mikael Den tors 10 feb. 2022 17:52Stefan Israelsson Tampe skrev: > Consider a memory barrier idiom constructed from > 0, (mk-stack) > 1. (enter x) > 2. (pause x) > 3. (leave x) > > The idea is that we create a separate stack object and when entering it, > we will swap the current stack with the one in the argument saving the > current stack in x and be in the 'child' state and move to a paused > position in case of a pause, when pausing stack x, we will return to where > after where entered saving the current position in stack and ip, and be in > state 'pause' and when we leave we will be in the state 'leave and move > to the old stack, using the current > ip. At first encounter the function stack frame is copied over hence there > will be a fork limited to the function only. > > This means that we essentially can define a generator as > (define (g x) > (let lp ((n 0)) > (if (< n 10) > (begin > (pause x) > (lp (+ n 1)))))) > > And use it as > (define (test) > (let ((x (mk-stack))) > (let lp () > (case (enter x) > ((pause) > (pk 'pause) > (lp)) > ((child) > (g x) > (leave x)))))))) > > A paused or leaved stack cannot be paused, an entered stack cannot be > entered and one cannot leave a paused stack, but enter a leaved stack. > > Anyhow this idea is modeled like a fork command instead of functional and > have the benefit over delimited continuations that one does not need to > copy the whole stack and potentially speed up generator like constructs. > But not only this, writing efficient prolog code is possible as well. We > could simplify a lot of the generation of prolog code, speed it up and also > improve compiler speed of prolog code significantly. > > How would we approach the prolog code. The simplest system is to use > return the > alternate pause stack when succeeding things becomes very simple, > > x = stack to pause to in case of failure > cc = the continuation > > ( (x cc) goal1 goal2) > :: (cc (goal1 (goal2 x)) > > ( (x cc) goal1 goal2) > :: (let ((xx (mkstack))) > (case (enter xx) > ((child) > (cc (goal2 xx))) > > ((pause) > (cc (goal2 x))))) > > Very elegant, and we also can use some heuristics to store already made > stacks when > leaving a stack and reuse at the next enter which is a common theme in > prolog, > > Anyhow we have an issue, consider the case where everythings > succeds forever. Then we will blow the stack . There is no concept of tail > calls here. So what you can do is the following for an , > > (let ((xx (mk-stack))) > (case (enter xx) > ((child) > (goal1 x (lambda (xxx) (pause xx xxx))) > > ((pause xxx) > (goal2 xxx cc)))) > > This enable cuts so that a cutted and (and!) in kanren lingo will use > (goal2 x cc) > > And we have tail calls! > > > I have a non jitted version guile working as a proof of concept. > > The drawback with this is if a function uses a lot of stack, it will be a > memory hog. > > WDYT? > > > > > > > > > > > > . > > >