ホーム >

Scheme

call/ccでジェネレータを実装する

(define-condition-type <stop-iteration> <condition> #f
  )

(define (make-generator proc)
  (let* ((next #f)
       (break #f)
       (yield (lambda arg (call/cc (lambda (cc) (set! next cc) (apply break arg)))))
       (result (lambda () (call/cc (lambda (cc) (set! break cc) (next)))))
       )
    (call/cc
     (lambda (return)
       (call/cc (lambda (cc) (set! next cc) (return result)))
       (proc yield)
       (call/cc (lambda (cc) (set! next cc)))
       (error <stop-iteration>)
       ))
    ))

使用例

(define (new-fib)
  (make-generator
   (lambda (yield)
     (let loop ((a 0) (b 1))
       (yield a)
       (loop b (+ a b))))))
(let ((f (new-fib)))
  (dotimes (i 10) (print (f))))

マクロユーティリティ

Gaucheで動作します。

(define-module macro-utilities
  (export with-gensyms
        once-only
        aif
        awhen
        ))
(select-module macro-utilities)

(define-macro (with-gensyms syms . body)
  `(let ,(map (lambda (s) `(,s (gensym ,(string-append (x->string s) "-")))) syms)
     ,@body)
  )

(define-macro (once-only names . body)
  (let ((gensyms (map (lambda (n) (gensym (x->string n))) names)))
    (list 'let (map (lambda (g) `(,g (gensym))) gensyms)
        (list 'quasiquote
                `(let ,(map (lambda (g n) (list (list 'unquote g) (list 'unquote n))) gensyms names)
                   ,(list 'unquote `(let ,(map (lambda (n g) (list n g)) names gensyms) ,@body))
                   )))
    ))

(define-macro (aif test then . rest)
  (let-optionals* rest ((else (if #f #f)))
  `(let ((it ,test))
     (if it ,then ,else)))
  )

(define-macro (awhen test . body)
  `(let ((it ,test)) (when it . ,body))
  )

(provide "macro-utilities")