Skip to content

Instantly share code, notes, and snippets.

@timm
Created February 25, 2012 04:01
Show Gist options
  • Save timm/1906354 to your computer and use it in GitHub Desktop.
Save timm/1906354 to your computer and use it in GitHub Desktop.
LUA for loops (in LISP)
#|
The LUA programming language supports iterators.
The LUA for loop takes some generate function and asks it to
produce a function that can return the next item.
A loop is then entered. The next item is generated. If it
is non-nil, then the body of the loop is called to consume
that item.
Otherwise, it exit.
The following LISP macro emulates that for command.
|#
(defmacro for ((item producer) &body consume)
(let ((step (gensym "STEP"))
(next (gensym "NEXT"))
(run (gensym "RUN")))
`(let ((,step ,producer))
(labels ((,next () (funcall ,step))
(,run (,item)
(when ,item
,@consume
(,run (,next)))))
(,run (,next))))))
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; EXAMPLE 1: generate a bunch of odd numbers
(defun odds(max)
(let ((i 0))
#'(lambda ()
(incf i)
(if (evenp i)
(incf i))
(if (<= i max)
i))))
(defun !for1 ()
(for (item (odds 10))
(print item)))
#|
(LET ((#:STEP1404 (ODDS 10)))
(LABELS ((#:NEXT1405 ()
(FUNCALL #:STEP1404))
(#:RUN1406 (ITEM)
(WHEN ITEM (PRINT ITEM) (#:RUN1406 (#:NEXT1405)))))
(#:RUN1406 (#:NEXT1405))))
CL-USER> (!for1)
1
3
5
7
9
NIL
|#
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; EXAMPLE 2: process all the odd,even items in a list
(defun oddeven (lst)
(let ((copy (copy-list lst)))
#'(lambda ()
(when lst
(let ((odd (pop copy))
(even (pop copy)))
(and odd
even
(list odd even)))))))
(defun !for2 ()
(for (pair (oddeven '(tim m toni f lucie f)))
(print pair)))
#|
(LET ((#:STEP1407 (ODDEVEN '(TIM M TONI F LUCIE F))))
(LABELS ((#:NEXT1408 ()
(FUNCALL #:STEP1407))
(#:RUN1409 (PAIR)
(WHEN PAIR (PRINT PAIR) (#:RUN1409 (#:NEXT1408)))))
(#:RUN1409 (#:NEXT1408))))
CL-USER> (!for2)
(TIM M)
(TONI F)
(LUCIE F)
NIL
|#
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; EXAMPLE 3: fibonacci numbers
(defun fibUpToMax (max)
(let ((i1 1)
(i2 1))
#'(lambda ()
(when (<= i1 max)
(let ((tmp i1))
(setf i1 i2)
(setf i2 (+ tmp i2))
tmp)))))
(defun !for3 ()
(for (num (fibUpToMax 20))
(print num)))
#|
(LET ((#:STEP1410 (FIBUPTOMAX 20)))
(LABELS ((#:NEXT1411 ()
(FUNCALL #:STEP1410))
(#:RUN1412 (NUM)
(WHEN NUM (PRINT NUM) (#:RUN1412 (#:NEXT1411)))))
(#:RUN1412 (#:NEXT1411))))
CL-USER> (!for3)
1
1
2
3
5
8
13
NIL
|#
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
; EXAMPLE 4:
; sys admin adds in a delay to your accessing
; (avoids congestion)
(defun recieve (&key (max 100) (buffer 10))
(let ((pause 5))
#'(lambda ()
(let (out)
(dotimes (i buffer)
(decf max)
(if (>= max 0)
(push (cpuIntensiveThing) out)))
(wait (* (random 1.0) pause))
out))))
(defun wait (n)
(dotimes (i (round n))
(format t "waiting~a~%" i)))
(defun cpuIntensiveThing ()
(random 100))
(defun !for4 ()
(for (item (recieve :max 22 :buffer 5))
(format t "~&received ====> ~a~%" item)))
#|
(LET ((#:STEP1645 (RECIEVE :MAX 22 :BUFFER 5)))
(LABELS ((#:NEXT1646 ()
(FUNCALL #:STEP1645))
(#:RUN1647 (ITEM)
(WHEN ITEM
(FORMAT T "~&received ====> ~a~%" ITEM)
(#:RUN1647 (#:NEXT1646)))))
(#:RUN1647 (#:NEXT1646))))
CL-USER> (load "forall.lisp") (!for4)
waiting0
waiting1
received ====> (83 61 39 71 17)
waiting0
waiting1
waiting2
waiting3
received ====> (39 27 6 39 80)
waiting0
waiting1
received ====> (65 61 41 90 52)
waiting0
waiting1
waiting2
waiting3
received ====> (43 82 29 51 62)
waiting0
waiting1
waiting2
waiting3
waiting4
received ====> (81 1)
waiting0
waiting1
waiting2
NIL
|#
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment