Skip to content

Instantly share code, notes, and snippets.

@bowbow99
Created December 3, 2010 14:30
Show Gist options
  • Select an option

  • Save bowbow99/727020 to your computer and use it in GitHub Desktop.

Select an option

Save bowbow99/727020 to your computer and use it in GitHub Desktop.
;;; generator っぽいものだとスッキリしそうなケースを思いついたので書いて
;;; みたけど、あまりスッキリしなかった
(define-condition stop-iteration (condition)
()
(:report (lambda (c s) (format s "Stop Iteration"))))
=> t
(defun plist-iterator (plist)
"generato iterator from plist."
(lambda ()
(block #1=#:iterator
(while (>= (length plist) 2)
(return-from #1#
(multiple-value-prog1
(values (car plist) (cadr plist))
(setf plist (cddr plist)))))
(signal 'stop-iteration))))
=> plist-iterator
;; 手動で funcall してみる
(setf iter (plist-iterator '(foo 1 bar 2 baz 3)))
=> #<lexical-closure: (anonymous)>
(funcall iter)
=> foo
=> 1
(funcall iter)
=> bar
=> 2
(funcall iter)
=> baz
=> 3
(funcall iter)
>> Stop Iteration
;; 止まるまで funcall し続ける
(setf iter (plist-iterator '(foo 1 bar 2 baz 3)))
=> #<lexical-closure: (anonymous)>
(handler-case
(loop
(multiple-value-bind (key value)
(funcall iter)
(format t "~S = ~S~%" key value)))
(stop-iteration (e) nil))
foo = 1
bar = 2
baz = 3
=> nil
;;; macro で generator 定義だけ少しスッキリさせた
(defmacro defgenerator (name (&rest args) &body body)
"Yield!!"
`(defun ,name (,@args)
(lambda ()
(block #1=#:iterator
(macrolet ((yield (value)
`(return-from #1# ,value)))
,@body
(signal 'stop-iteration))))))
=> defgenerator
(defgenerator plist-iterator (plist)
(while (>= (length plist) 2)
(yield (multiple-value-prog1
(values (first plist) (second plist))
(setf plist (cddr plist))))))
=> plist-iterator
(setf iter (plist-iterator '(foo 1 bar 2 baz 3)))
=> #<lexical-closure: (anonymous)>
(handler-case
(loop
(multiple-value-bind (key value)
(funcall iter)
(format t "~S = ~S~%" key value)))
(stop-iteration (e) nil))
foo = 1
bar = 2
baz = 3
=> nil
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment