diff --git a/goof.scm b/goof.scm index 642a2a7..439f4e3 100644 --- a/goof.scm +++ b/goof.scm @@ -33,15 +33,15 @@ ;; trying to understand the iterator protocol. - (use-modules (helpers) ((srfi srfi-1) #:select (circular-list)) (srfi srfi-71) - (rnrs io simple)) + (rnrs io simple) + (ice-9 futures)) (define-aux-syntaxes ;; Auxiliary syntax for the loop clauses - :when :unless :break :final :let :let* :subloop + :when :unless :break :final :let :let* :subloop :for :acc ;; Auxiliary syntax for the iterators. :gen) @@ -51,23 +51,31 @@ (define-syntax loop - (syntax-rules () + (syntax-rules (=>) + ((loop () => expr body ...) + (let () expr)) + ((loop () body ...) + (let () body ...)) + ((loop name () => expr body ...) + expr) + ((loop name () body ...) + (if #f #f)) ((loop (clauses ...) body ...) (cl (loop (clauses ...) body ...) loop-name - (()) (()) (()) (()) (()) () (()) (()) (()) + (()) (()) (()) (()) (()) () (()) (()) (()) () (clauses ...) body ... (loop-name))) ((loop name (clauses ...) . body) (cl (loop name (clauses ...) . body) name - (()) (()) (()) (()) (()) () (()) (()) (()) + (()) (()) (()) (()) (()) () (()) (()) (()) () (clauses ...) . body)))) (define-syntax push-new-subloop (syntax-rules () - ((_ orig name (lets ...) (accs ...) (vars ...) (checks ...) (refs ...) f (ul ...) (uw ...) (ub ...) clauses . body) + ((_ orig name (lets ...) (accs ...) (vars ...) (checks ...) (refs ...) f (ul ...) (uw ...) (ub ...) uf clauses . body) (cl orig name (() lets ...) (() accs ...) @@ -78,47 +86,58 @@ (() ul ...) (() uw ...) (() ub ...) + uf clauses . body)))) ;; Clauses sorts all the clauses into subloops and positions everything where it should be. (define-syntax cl - (syntax-rules (=> in :when :unless :break :final :let :let* :subloop) - ((_ orig name l a v c r f ul uw ub () => expr . body) - (emit orig name l a v c r f ul uw ub expr . body)) - ((_ orig name l a v c r f ul uw ub () . body) - (emit orig name l a v c r f ul uw ub (if #f #f) . body)) + (syntax-rules (=> :for :acc :when :unless :break :final :let :let* :subloop) + ((_ orig name l a v c r f ul uw ub uf () => expr . body) + (emit orig name l a v c r f ul uw ub uf expr . body)) + ((_ orig name l a v c r f ul uw ub uf () . body) + (emit orig name l a v c r f ul uw ub uf (if #f #f) . body)) + ;; USER LETS + ((_ orig name l a v c r f ((cur-ul ...) . ul-rest) uw ub uf (:let (id id* ... expr) clauses ...) . body) + (cl orig name l a v c r f ((cur-ul ... (:let id id* ... expr)) . ul-rest) uw ub uf (clauses ...) . body)) + ((_ orig name l a v c r f ((cur-ul ...) . ul-rest) uw ub uf (:let* (id id* ... expr) clauses ...) . body) + (cl orig name l a v c r f ((cur-ul ... (:let* id id* ... expr)) . ul-rest) uw ub uf (clauses ...) . body)) ;; user-whens - ((_ orig name l a v c r f ul ((cur-uw ...) . uw-rest) ub (:when test clauses ...) . body) - (cl orig name l a v c r f ul ((cur-uw ... test) . uw-rest) ub (clauses ...) . body)) - ((_ orig name l a v c r f ul ((cur-uw ...) . uw-rest) ub (:unless test clauses ...) . body) - (cl orig name l a v c r f ul ((cur-uw ... (not test)) . uw-rest) ub (clauses ...) . body)) + ((_ orig name l a v c r f ul ((cur-uw ...) . uw-rest) ub uf (:when test clauses ...) . body) + (cl orig name l a v c r f ul ((cur-uw ... test) . uw-rest) ub uf (clauses ...) . body)) + ((_ orig name l a v c r f ul ((cur-uw ...) . uw-rest) ub uf (:unless test clauses ...) . body) + (cl orig name l a v c r f ul ((cur-uw ... (not test)) . uw-rest) ub uf (clauses ...) . body)) ;; USER BREAKS ;; This pushes a #t to the user when expression, thus forcing a subloop if a for-clause is found afterwards. - ((_ orig name l a v c r f ul ((cur-uw ...) . uw-rest) ((cur-ub ...) . ub-rest) (:break expr clauses ...) . body) - (cl orig name l a v c r f ul ((cur-uw ... #t) . uw-rest) ((cur-ub ... expr) . ub-rest) (clauses ...) . body)) - ;; USER LETS - ((_ orig name l a v c r f ((cur-ul ...) . ul-rest) uw ub (:let (id id* ... expr) clauses ...) . body) - (cl orig name l a v c r f ((cur-ul ... (:let id id* ... expr)) . ul-rest) uw ub (clauses ...) . body)) - ((_ orig name l a v c r f ((cur-ul ...) . ul-rest) uw ub (:let* (id id* ... expr) clauses ...) . body) - (cl orig name l a v c r f ((cur-ul ... (:let* id id* ... expr)) . ul-rest) (clauses ...) . body)) + ((_ orig name l a v c r f ul ((cur-uw ...) . uw-rest) ((cur-ub ...) . ub-rest) uf (:break expr clauses ...) . body) + (cl orig name l a v c r f ul ((cur-uw ... #t) . uw-rest) ((cur-ub ... expr) . ub-rest) uf (clauses ...) . body)) + ;; user final + ;; This pushes a #t to the user when expression, thus forcing a subloop if a for-clause is found afterwards. + ((_ orig name l a v c r f ul ((cur-uw ...) . uw-rest) ub (cur-uf ...) (:final expr clauses ...) . body) + (cl orig name l a v c r f ul ((cur-uw ... #t) . uw-rest) ub (cur-uf ... expr) (clauses ...) . body)) + ;; Explicit subloop. Shorthand for (:when #t) - ((_ orig name l a v c r f ul ((cur-uw ...) . uw-rest) ub (:subloop clauses ...) . body) - (cl orig name l a v c r f ul ((cur-uw ... #t) . uw-rest) ub (clauses ...) . body)) + ((_ orig name l a v c r f ul ((cur-uw ...) . uw-rest) ub uf (:subloop clauses ...) . body) + (cl orig name l a v c r f ul ((cur-uw ... #t) . uw-rest) ub uf (clauses ...) . body)) ;; :for-clauses ;; found a for clause when we have a :when or :unless clause. Push new subloop - ((_ orig name l a v c r f ul ((uw uw* ...) . uw-rest) ub ((for-rest ...) clauses ...) . body) - (push-new-subloop orig name l a v c r f ul ((uw uw* ...) . uw-rest) ub ((for-rest ...) clauses ...) . body)) + ((_ orig name l a v c r f ul ((uw uw* ...) . uw-rest) ub uf ((:for for-rest ...) clauses ...) . body) + (push-new-subloop orig name l a v c r f ul ((uw uw* ...) . uw-rest) ub uf ((:for for-rest ...) clauses ...) . body)) ;; For clause with a sequence creator. - ((_ orig name l a v c r f ul uw ub ((id ids ... (iterator source ...)) clauses ...) . body) - (iterator ((id ids ...) (source ...)) cl-next orig name l a v c r f ul uw ub (clauses ...) . body)) - + ((_ orig name l a v c r f ul uw ub uf ((:for id ids ... (iterator source ...)) clauses ...) . body) + (iterator ((id ids ...) (source ...)) cl-next orig name l a v c r f ul uw ub uf (clauses ...) . body)) + + ((_ orig name l a v c r f ul uw ub uf ((:acc id ids ... (accumulator source ...)) clauses ...) . body) + (accumulator :acc ((id ids ...) (source ...)) cl-next orig name l a v c r f ul uw ub uf (clauses ...) . body)) + ;; no :acc or :for: imlplicit for! + ((_ orig name l a v c r f ul uw ub uf ((id ids ... (iterator source ...)) clauses ...) . body) + (cl orig name l a v c r f ul uw ub uf ((:for id ids ... (iterator source ...)) clauses ...) . body)) ;; ERROR HANDLING? - ((_ orig name l a v c r f ul uw ub (clause . rest) . body) + ((_ orig name l a v c r f ul uw ub uf (clause . rest) . body) (syntax-error "Invalid clause in loop" clause orig)) )) @@ -129,7 +148,7 @@ ;; into the outer loops. Since accumulators need to be available in the (final-fun ...), they need to be visible also ;; in the outer loops if the loop exits there. (define-syntax cl-next - (syntax-rules () + (syntax-rules (:for :acc) ((_ (new-lets ...) ((accvar accinit accupdate) ...) (new-vars ...) (new-checks ...) (new-refs ...) (new-finals ...) orig name ((lets ...)) @@ -137,7 +156,7 @@ ((vars ...)) ((checks ...)) ((refs ...)) - (finals ...) ul uw ub clauses . body) + (finals ...) ul uw ub uf clauses . body) (cl orig name ((lets ... new-lets ...)) ((accs ... (accvar accinit accupdate) ...)) @@ -145,7 +164,7 @@ ((checks ... new-checks ...)) ((refs ... new-refs ...)) (finals ... new-finals ...) - ul uw ub clauses . body)) + ul uw ub uf clauses . body)) ;; We have ONE subloop! ((_ (new-lets ...) ((accvar accinit accupdate) ...) (new-vars ...) (new-checks ...) (new-refs ...) (new-finals ...) orig name @@ -154,7 +173,7 @@ ((vars ...) . vars-rest) ((checks ...) . checks-rest) ((refs ...) . refs-rest) - (finals ...) ul uw ub clauses . body) + (finals ...) ul uw ub uf clauses . body) (cl orig name ((lets ... new-lets ...) . lets-rest) ((accs ... (accvar accvar accupdate) ...) ((oldacc oldinit oldupdate) ... (accvar accinit accvar) ...)) @@ -162,7 +181,7 @@ ((checks ... new-checks ...) . checks-rest) ((refs ... new-refs ...) . refs-rest) (finals ... new-finals ...) - ul uw ub clauses . body)) + ul uw ub uf clauses . body)) ;; We have several subloops! ((_ (new-lets ...) ((accvar accinit accupdate) ...) (new-vars ...) (new-checks ...) (new-refs ...) (new-finals ...) orig name @@ -171,7 +190,7 @@ ((vars ...) . vars-rest) ((checks ...) . checks-rest) ((refs ...) . refs-rest) - (finals ...) ul uw ub clauses . body) + (finals ...) ul uw ub uf clauses . body) (cl orig name ((lets ... new-lets ...) . lets-rest) ((accs ... (accvar accvar accupdate) ...) ((oldacc oldinit oldupdate) ... (accvar accvar accvar) ...) ... @@ -180,7 +199,7 @@ ((checks ... new-checks ...) . checks-rest) ((refs ... new-refs ...) . refs-rest) (finals ... new-finals ...) - ul uw ub clauses . body)) + ul uw ub uf clauses . body)) )) (define-syntax user-let @@ -224,7 +243,8 @@ ((checks ...)) ((refs ...)) ((final-binding final-value) ...) - ((user-lets ...)) ((user-whens ...)) ((user-breaks ...)) final-expr . body) + ((user-lets ...)) ((user-whens ...)) ((user-breaks ...)) uf + final-expr . body) (let* (lets ...) (define (final-fun final-binding ...) final-expr) @@ -234,7 +254,10 @@ (let (refs ...) (user-let () () (user-lets ...) (if (and user-whens ...) - (let-kw-form name (loopy-loop (accvar accstep) ... (var step) ...) + (let-kw-form name + (final-fun final-value ...) + uf + (loopy-loop (accvar accstep) ... (var step) ...) (if (or user-breaks ...) (final-fun final-value ...) (let () (if #f #f) . body))) @@ -254,6 +277,7 @@ (ul-next ... (user-lets ...)) (uw-next ... (user-whens ...)) (ub-next ... (user-breaks ...)) + uf final-expr . body) (let* ((final-fun (lambda (final-binding ...) final-expr)) @@ -280,6 +304,7 @@ (ul-next ...) (uw-next ...) (ub-next ...) + uf . body))) (outer-loop accvar ... step ...)))))))))) @@ -298,6 +323,7 @@ ((user-lets ...)) ((user-whens ...)) ((user-breaks ...)) + uf . body) (let* (lets ...) (let innermost-loop ((accvar accinit) ... @@ -310,7 +336,7 @@ (cond ((or user-breaks ...) final) (else - (let-kw-form name (innermost-loop (accvar accstep) ... (var step) ...) + (let-kw-form name final uf (innermost-loop (accvar accstep) ... (var step) ...) . body))) (innermost-loop accvar ... step ...)))))))) @@ -327,6 +353,7 @@ (ul-next ... (user-lets ...)) (uw-next ... (user-whens ...)) (ub-next ... (user-breaks ...)) + uf . body) (let* (lets ...) (let intermediate-loop ((accvar accinit) ... @@ -351,6 +378,7 @@ (ul-next ...) (uw-next ...) (ub-next ...) + uf . body)) (intermediate-loop accvar ... step ...)))))))))) @@ -362,7 +390,7 @@ (define (update-name params name val) (cond - ((null? params) (error "unknown loop parameter name " name (list '=> name val))) + ((null? params) (error "unknown loop variable name " name (list '=> name val))) ((syntax= name (caar params)) (cons (list (caar params) val) (cdr params))) (else @@ -374,7 +402,7 @@ (define-syntax let-kw-form (syntax-rules () - ((_ macro-name (loop-name (var step) ...) . body) + ((_ macro-name final-fun (user-finals ...) (loop-name (var step) ...) . body) (let-syntax ((macro-name (lambda (stx) (with-ellipsis ::: @@ -382,7 +410,10 @@ (params (list #'(var step) ...))) (if (null? lst) (with-syntax ((((v s) :::) params)) - #'(loop-name s :::)) + #'(let ((v s) :::) + (if (or user-finals ...) + final-fun + (loop-name v :::)))) (syntax-case (car lst) (=>) ((=> name val) (loop (cdr lst) (update-name params #'name #'val))) @@ -401,19 +432,19 @@ (define-syntax loop/sum (syntax-rules () ((_ (clauses ...) body ...) - (loop (clauses ... (acc (summing (let () body ...)))) => acc)))) + (loop (clauses ... (:acc acc (summing (let () body ...)))) => acc)))) (define-syntax loop/product (syntax-rules () ((_ (clauses ...) body ...) - (loop (clauses ... (acc (multiplying (let () body ...)))) => acc)))) + (loop (clauses ... (:acc acc (multiplying (let () body ...)))) => acc)))) (define sentinel (list 'unique)) (define-syntax loop/first (syntax-rules () ((_ (clauses ...) body ...) - (loop loop-name ((acc (folding sentinel)) clauses ... :break (not (eq? sentinel acc))) + (loop loop-name (clauses ... (:acc acc (folding sentinel)) :break (not (eq? sentinel acc))) => (if (eq? sentinel acc) #f acc) (let ((result (let () body ...))) (loop-name (=> acc result))))))) @@ -421,9 +452,34 @@ (define-syntax loop/last (syntax-rules () ((_ (clauses ...) body ...) - (loop loop-name ((acc (folding sentinel)) clauses ...) => (if (eq? sentinel acc) #f acc) + (loop loop-name (clauses ... (:acc acc (folding sentinel))) => (if (eq? sentinel acc) #f acc) (let ((result (let () body ...))) (loop-name (=> acc result))))))) - + +(define-syntax loop/and + (syntax-rules () + ((_ (clauses ...) body ...) + (loop loop-name (clauses ... (:acc acc (folding #t))) + => acc + (let ((res (let () body ...))) + (if res + (loop-name (=> acc res)) + #f)))))) + +(define-syntax loop/or + (syntax-rules () + ((_ (clauses ...) body ...) + (loop loop-name (clauses ...) + => #f + (or (let () body ...) (loop-name)))))) + +(define-syntax loop/list/parallel + (syntax-rules () + ((_ (clauses ...) body ...) + (loop (clauses ... (:acc futures (listing-reverse (future (let () body ...))))) + => (loop ((:for future (in-list futures)) + (:acc futures2 (listing-reverse (touch future)))) + => futures2))))) + diff --git a/iterators.scm b/iterators.scm index f59a0a6..547ca3d 100644 --- a/iterators.scm +++ b/iterators.scm @@ -214,23 +214,20 @@ ((up-from (() . args) next . rest) (up-from ((var) . args) next . rest)) ((up-from ((var) (start (to limit) (by step))) next . rest) - (next ((s start) (l limit) (e step)) () - ((var s (+ var e))) ((>= var l)) () () . rest)) + (next ((s start) (l limit) (e step)) + () + ((var s (+ var e))) + ((>= var l)) + () () . rest)) ((up-from ((var) (start (to limit))) next . rest) - (next ((s start) (l limit))() - ((var s (+ var 1))) + (next ((s start) (l limit)) () ((var s (+ var 1))) ((>= var l)) () () . rest)) ((up-from ((var) (start (by step))) next . rest) (next ((s start) (e step))() ((var s (+ var e))) () () () . rest)) ((up-from ((var) (start)) next . rest) - (next ((s start)) - () - ((var s (+ var 1))) - () - () - () - . rest)) + (next ((s start)) () ((var s (+ var 1))) + () () () . rest)) ;; Extra convenience, make it act like (in-range ...) from racket, but only for positive numbers. ((up-from ((var) (start limit step)) next . rest) (next ((s start) (l limit) (e step)) () ((var s (+ var e))) ((>= var l)) () () . rest)) @@ -248,42 +245,28 @@ () ((var (- s e) (- var e))) ((< var l)) - () - () - . rest)) + () () . rest)) ((down-from ((var) (start (to limit))) next . rest) - (next ((s start) (l limit)) - () - ((var (- s 1) (- var 1))) - ((< var l)) - () - () - . rest)) + (next ((s start) (l limit)) () ((var (- s 1) (- var 1))) + ((< var l)) () () . rest)) ((down-from ((var) (start (by step))) next . rest) - (next ((s start) (e step)) - () - ((var (- s e) (- var e))) - () - () - () - . rest)) + (next ((s start) (e step)) () ((var (- s e) (- var e))) + () () () . rest)) ((down-from ((var) (start)) next . rest) - (next ((s start)) - () - ((var (- s 1) (- var 1))) - () - () - () - . rest)) - )) + (next ((s start)) () ((var (- s 1) (- var 1))) + () () () . rest)) + ((down-from ((var) (start limit step)) next . rest) + (next ((s start) (l limit) (e step)) () ((var (- s e) (- var e))) ((< var l)) () () . rest)) + ((down-from ((var) (start limit)) next . rest) + (down-from ((var) (start limit 1)) next . rest)))) (define-syntax accumulating - (syntax-rules (initial if) - ((accumulating (kons final init) ((var) . x) next . rest) - (accumulating (kons final init) ((var cursor) . x) next . rest)) - ((accumulating (kons final init) ((var cursor) ((initial i) . x)) n . rest) - (accumulating (kons final i) ((var cursor) x) n . rest)) - ((accumulating (kons final init) ((var cursor) (expr (if check))) n . rest) + (syntax-rules (initial if :acc) + ((accumulating :acc (kons final init) ((var) . x) next . rest) + (accumulating :acc (kons final init) ((var cursor) . x) next . rest)) + ((accumulating :acc (kons final init) ((var cursor) ((initial i) . x)) n . rest) + (accumulating :acc (kons final i) ((var cursor) x) n . rest)) + ((accumulating :acc (kons final init) ((var cursor) (expr (if check))) n . rest) (n ((tmp-kons kons)) ((cursor init (if check (tmp-kons expr cursor) cursor))) () @@ -291,7 +274,7 @@ () ((var (final cursor))) . rest)) - ((accumulating (kons final init) ((var cursor) (expr)) n . rest) + ((accumulating :acc (kons final init) ((var cursor) (expr)) n . rest) (n ((tmp-kons kons)) ((cursor init (tmp-kons expr cursor))) () @@ -301,32 +284,32 @@ . rest)))) (define-syntax folding - (syntax-rules (if) - ((_ ((var) (init update (if guard))) n . rest) + (syntax-rules (if :acc) + ((_ :acc ((var) (init update (if guard))) n . rest) (n () ((var init (if guard update var))) () () () ((var var)) . rest)) - ((_ ((var) (init update)) n . rest) + ((_ :acc ((var) (init update)) n . rest) (folding ((var) (init update (if #t))) n . rest)) - ((_ ((var) (init)) n . rest) + ((_ :acc ((var) (init)) n . rest) (folding ((var) (init var (if #t))) n . rest)))) ;;> \macro{(for x [pair] (listing expr))} (define-syntax listing - (syntax-rules () - ((listing args next . rest) - (accumulating (cons reverse '()) args next . rest)))) + (syntax-rules (:acc) + ((listing :acc args next . rest) + (accumulating :acc (cons reverse '()) args next . rest)))) ;;> \macro{(for x [pair] (listing-reverse expr))} (define-syntax listing-reverse - (syntax-rules () - ((listing-reverse args next . rest) - (accumulating (cons (lambda (x) x) '()) args next . rest)))) + (syntax-rules (:acc) + ((listing-reverse :acc args next . rest) + (accumulating :acc (cons (lambda (x) x) '()) args next . rest)))) (define (append-reverse rev tail) (if (null? rev) tail (append-reverse (cdr rev) (cons (car rev) tail)))) @@ -334,29 +317,29 @@ ;;> \macro{(for x [pair] (appending expr))} (define-syntax appending - (syntax-rules () - ((appending args next . rest) - (accumulating (append-reverse reverse '()) args next . rest)))) + (syntax-rules (:acc) + ((appending :acc args next . rest) + (accumulating :acc (append-reverse reverse '()) args next . rest)))) ;;> \macro{(for x [pair] (appending-reverse expr))} (define-syntax appending-reverse - (syntax-rules () - ((appending-reverse args next . rest) - (accumulating (append-reverse (lambda (x) x) '()) args next . rest)))) + (syntax-rules (:acc) + ((appending-reverse :acc args next . rest) + (accumulating :acc (append-reverse (lambda (x) x) '()) args next . rest)))) ;;> \macro{(for x (summing expr))} (define-syntax summing - (syntax-rules () - ((summing args next . rest) - (accumulating (+ (lambda (x) x) 0) args next . rest)))) + (syntax-rules (:acc) + ((summing :acc args next . rest) + (accumulating :acc (+ (lambda (x) x) 0) args next . rest)))) ;;> \macro{(for x (multiplying expr))} (define-syntax multiplying - (syntax-rules () - ((multiplying args next . rest) + (syntax-rules (:acc) + ((multiplying :acc args next . rest) (accumulating (* (lambda (x) x) 1) args next . rest)))) @@ -380,10 +363,10 @@ ((_ ((id) (source)) n . rest) (n ((gen (generator-cycle source))) () - ((id (gen) (gen))) - ((eof-object? id)) () () + ((id (gen))) + () . rest))))