Rotating generator (a generator factory pattern)

Started by Alisaxy, August 01, 2015, 09:09:22 AM

Previous topic - Next topic

Alisaxy

I was trying to wrap my head around all of the power newLISP offers, figuring that the lack of coroutines or tasklets which I very much need, wouldn't be much of a problem to fix. It appears I was right and here's a slightly more advanced rotating generator factory pattern. One could easily adopt it for any type of a generator factory. Who needs "yield", right?



self-modifying version:

(setf rotating-tasklet^ (fn (loc body)
 (rotate body)
  (letex (loc loc body body)
   (expand (setf loc (fn (arg)
    (pop loc -1)
    (push (first (rotate 'body -1)) loc -1)
    'first-of-body-goes-here))))))

slightly more concise eval version:

(setf rotating-tasklet^ (fn (loc body)
 (rotate body)
  (letex (loc loc body body)
   (expand (setf loc (fn (arg)
   (eval (first (rotate 'body -1)))))))))

usage:

(rotating-tasklet^ 'rot
 '((+ 10 arg)
   (+ 11 arg)
   (+ 12 arg)))
(rotating-tasklet^ 'rotX
  '((println "first")
    (println "second")
    (println "third")))
(rotX)
(println (rot 1000))
(rotX)
(println (rot 2500))
(rotX)
(println (rot 333))

Not sure which version is better. I have a sub-conscious distrust for eval (all those years using js in my day job), but it is probably the better version. I anticipate though that the first version would be more elegant if the function would become more complex.



slightly shorter no eval version using setf instead of pop/push

(setf rotating-tasklet^ (fn (loc body)
 (rotate body)
  (letex (loc loc body body)
   (expand (setf loc (fn (arg)
    (setf (last loc) (first (rotate 'body -1)))
    'first-of-body-goes-here))))))


Just a suggestion: a way to refer to the function itself in an $it fashion would make newLISP an even more powerful language. Right now if you wish to relocate or copy such construct you would have to provide it with a precise future location, which can get unwieldy and just isn't all that elegant to be honest. With a let's call it a "$self" one could forgo such needless gymnastics.



EDIT: incorporated setf into all patterns.

rrq

#1
Nice idea. I assume the 'rot in setting rotX should be 'rotX rather.



Though maybe you would call these "generators" rather than "tasklets"? Or, focussing on that they provide different behaviour upon each invocation, maybe you'd call it state machine; with something for conditional branching, you'll have a Turing machine.



Anyhow, self modifying code is always fun.

Alisaxy

#2
Quote from: "ralph.ronnquist"Nice idea. I assume the 'rot in setting rotX should be 'rotX rather.


Oops, a typo! Yeah, should be "rotX" or any location to the generator in question. Could be a path to a list element like this "(list-name 0)". Yes, "generator" would be more appropriate, since tasklets are basically software thread emulations whilst generators are just yielding functions.