UNB/ CS/ David Bremner/ teaching/ cs4613/ lectures/ lecture15/ generator.rkt
#lang plait
(define yield-param (make-parameter
                     (lambda (v) (error 'yield! "outside generator"))))

(define (yield v) ((parameter-ref yield-param) v))
(define-syntax-rule (generator (arg) exprs ...)
  (let ([last-checkpoint (none)])
    (lambda (v)
      (let/cc dyn-k ;; generator call site
        (parameterize ([yield-param
                        (lambda (v)
                          (let/cc gen-k ;; yield call site
                            (begin
                              (set! last-checkpoint
                                    (some gen-k))
                              (dyn-k v))))])
          (type-case (Optionof ('a -> 'b)) last-checkpoint
              [(none) (let ([arg v]) (begin exprs ...))]
              [(some k) (k v)])))
    )))

(define g1
  (generator (v)
      (letrec ([loop (lambda (n)
                       (begin
                         (yield n)
                         (loop (+ n 1))))])
        (loop v))))

(g1 10)  (g1 10)  (g1 10)

(define g2
  (generator (v)
      (letrec ([loop (lambda (n)
                       (loop (+ (yield n) n)))])
        (loop v))))

(g2 10)  (g2 10)  (g2 10)