~ chicken-core (chicken-5) /tests/ec-tests.scm
Trap1; <PLAINTEXT>2; Examples for Eager Comprehensions in [outer..inner|expr]-Convention3; ===================================================================4;5; sebastian.egner@philips.com, Eindhoven, The Netherlands, 26-Dec-2007.6; Scheme R5RS (incl. macros), SRFI-23 (error).7;8; Running the examples in Scheme48 (version 1.1):9; ,open srfi-2310; ,load ec.scm11; (define my-open-output-file open-output-file)12; (define my-call-with-input-file call-with-input-file)13; ,load examples.scm14;15; Running the examples in PLT/DrScheme (version 317):16; (load "ec.scm")17; (define (my-open-output-file filename)18; (open-output-file filename 'replace 'text) )19; (define (my-call-with-input-file filename thunk)20; (call-with-input-file filename thunk 'text) )21; (load "examples.scm")22;23; Running the examples in SCM (version 5d7):24; (require 'macro) (require 'record)25; (load "ec.scm")26; (define my-open-output-file open-output-file)27; (define my-call-with-input-file call-with-input-file)28; (load "examples.scm")2930(import ec)313233(define my-open-output-file open-output-file)34(define my-call-with-input-file call-with-input-file)353637; Tools for checking results38; ==========================3940(define (my-equal? x y)41 (cond42 ((or (boolean? x)43 (null? x)44 (symbol? x)45 (char? x)46 (input-port? x)47 (output-port? x) )48 (eqv? x y) )49 ((string? x)50 (and (string? y) (string=? x y)) )51 ((vector? x)52 (and (vector? y)53 (my-equal? (vector->list x) (vector->list y)) ))54 ((pair? x)55 (and (pair? y)56 (my-equal? (car x) (car y))57 (my-equal? (cdr x) (cdr y)) ))58 ((real? x)59 (and (real? y)60 (eqv? (exact? x) (exact? y))61 (if (exact? x)62 (= x y)63 (< (abs (- x y)) (/ 1 (expt 10 6))) ))) ; will do here64 (else65 (error "unrecognized type" x) )))6667(define my-check-correct 0)68(define my-check-wrong 0)6970(define-syntax my-check71 (syntax-rules (=>)72 ((my-check ec => desired-result)73 (begin74 (newline)75 (write (quote ec))76 (newline)77 (let ((actual-result ec))78 (display " => ")79 (write actual-result)80 (if (my-equal? actual-result desired-result)81 (begin82 (display " ; correct")83 (set! my-check-correct (+ my-check-correct 1)) )84 (begin85 (display " ; *** wrong ***, desired result:")86 (newline)87 (display " => ")88 (write desired-result)89 (set! my-check-wrong (+ my-check-wrong 1)) ))90 (newline) )))))919293; ==========================================================================94; do-ec95; ==========================================================================9697(my-check98 (let ((x 0)) (do-ec (set! x (+ x 1))) x)99 => 1)100101(my-check102 (let ((x 0)) (do-ec (:range i 10) (set! x (+ x 1))) x)103 => 10)104105(my-check106 (let ((x 0)) (do-ec (:range n 10) (:range k n) (set! x (+ x 1))) x)107 => 45)108109110; ==========================================================================111; list-ec and basic qualifiers112; ==========================================================================113114(my-check (list-ec 1) => '(1))115116(my-check (list-ec (:range i 4) i) => '(0 1 2 3))117118(my-check (list-ec (:range n 3) (:range k (+ n 1)) (list n k))119 => '((0 0) (1 0) (1 1) (2 0) (2 1) (2 2)) )120121(my-check122 (list-ec (:range n 5) (if (even? n)) (:range k (+ n 1)) (list n k))123 => '((0 0) (2 0) (2 1) (2 2) (4 0) (4 1) (4 2) (4 3) (4 4)) )124125(my-check126 (list-ec (:range n 5) (not (even? n)) (:range k (+ n 1)) (list n k))127 => '((1 0) (1 1) (3 0) (3 1) (3 2) (3 3)) )128129(my-check130 (list-ec (:range n 5)131 (and (even? n) (> n 2))132 (:range k (+ n 1))133 (list n k) )134 => '((4 0) (4 1) (4 2) (4 3) (4 4)) )135136(my-check137 (list-ec (:range n 5)138 (or (even? n) (> n 3))139 (:range k (+ n 1))140 (list n k) )141 => '((0 0) (2 0) (2 1) (2 2) (4 0) (4 1) (4 2) (4 3) (4 4)) )142143(my-check144 (let ((x 0)) (list-ec (:range n 10) (begin (set! x (+ x 1))) n) x)145 => 10 )146147(my-check148 (list-ec (nested (:range n 3) (:range k n)) k)149 => '(0 0 1) )150151152; ==========================================================================153; Other comprehensions154; ==========================================================================155156(my-check (append-ec '(a b)) => '(a b))157(my-check (append-ec (:range i 0) '(a b)) => '())158(my-check (append-ec (:range i 1) '(a b)) => '(a b))159(my-check (append-ec (:range i 2) '(a b)) => '(a b a b))160161(my-check (string-ec #\a) => (string #\a))162(my-check (string-ec (:range i 0) #\a) => "")163(my-check (string-ec (:range i 1) #\a) => "a")164(my-check (string-ec (:range i 2) #\a) => "aa")165166(my-check (string-append-ec "ab") => "ab")167(my-check (string-append-ec (:range i 0) "ab") => "")168(my-check (string-append-ec (:range i 1) "ab") => "ab")169(my-check (string-append-ec (:range i 2) "ab") => "abab")170171(my-check (vector-ec 1) => (vector 1))172(my-check (vector-ec (:range i 0) i) => (vector))173(my-check (vector-ec (:range i 1) i) => (vector 0))174(my-check (vector-ec (:range i 2) i) => (vector 0 1))175176(my-check (vector-of-length-ec 1 1) => (vector 1))177(my-check (vector-of-length-ec 0 (:range i 0) i) => (vector))178(my-check (vector-of-length-ec 1 (:range i 1) i) => (vector 0))179(my-check (vector-of-length-ec 2 (:range i 2) i) => (vector 0 1))180181(my-check (sum-ec 1) => 1)182(my-check (sum-ec (:range i 0) i) => 0)183(my-check (sum-ec (:range i 1) i) => 0)184(my-check (sum-ec (:range i 2) i) => 1)185(my-check (sum-ec (:range i 3) i) => 3)186187(my-check (product-ec 1) => 1)188(my-check (product-ec (:range i 1 0) i) => 1)189(my-check (product-ec (:range i 1 1) i) => 1)190(my-check (product-ec (:range i 1 2) i) => 1)191(my-check (product-ec (:range i 1 3) i) => 2)192(my-check (product-ec (:range i 1 4) i) => 6)193194(my-check (min-ec 1) => 1)195(my-check (min-ec (:range i 1) i) => 0)196(my-check (min-ec (:range i 2) i) => 0)197198(my-check (max-ec 1) => 1)199(my-check (max-ec (:range i 1) i) => 0)200(my-check (max-ec (:range i 2) i) => 1)201202(my-check (first-ec #f 1) => 1)203(my-check (first-ec #f (:range i 0) i) => #f)204(my-check (first-ec #f (:range i 1) i) => 0)205(my-check (first-ec #f (:range i 2) i) => 0)206207(my-check208 (let ((last-i -1))209 (first-ec #f (:range i 10) (begin (set! last-i i)) i)210 last-i )211 => 0 )212213(my-check (last-ec #f 1) => 1)214(my-check (last-ec #f (:range i 0) i) => #f)215(my-check (last-ec #f (:range i 1) i) => 0)216(my-check (last-ec #f (:range i 2) i) => 1)217218(my-check (any?-ec #f) => #f)219(my-check (any?-ec #t) => #t)220(my-check (any?-ec (:range i 2 2) (even? i)) => #f)221(my-check (any?-ec (:range i 2 3) (even? i)) => #t)222223(my-check (every?-ec #f) => #f)224(my-check (every?-ec #t) => #t)225(my-check (every?-ec (:range i 2 2) (even? i)) => #t)226(my-check (every?-ec (:range i 2 3) (even? i)) => #t)227(my-check (every?-ec (:range i 2 4) (even? i)) => #f)228229(my-check230 (let ((sum-sqr (lambda (x result) (+ result (* x x)))))231 (fold-ec 0 (:range i 10) i sum-sqr) )232 => 285 )233234(my-check235 (let ((minus-1 (lambda (x) (- x 1)))236 (sum-sqr (lambda (x result) (+ result (* x x)))))237 (fold3-ec (error "wrong") (:range i 10) i minus-1 sum-sqr) )238 => 284 )239240(my-check241 (fold3-ec 'infinity (:range i 0) i min min)242 => 'infinity )243244245; ==========================================================================246; Typed generators247; ==========================================================================248249(my-check (list-ec (:list x '()) x) => '())250(my-check (list-ec (:list x '(1)) x) => '(1))251(my-check (list-ec (:list x '(1 2 3)) x) => '(1 2 3))252(my-check (list-ec (:list x '(1) '(2)) x) => '(1 2))253(my-check (list-ec (:list x '(1) '(2) '(3)) x) => '(1 2 3))254255(my-check (list-ec (:string c "") c) => '())256(my-check (list-ec (:string c "1") c) => '(#\1))257(my-check (list-ec (:string c "123") c) => '(#\1 #\2 #\3))258(my-check (list-ec (:string c "1" "2") c) => '(#\1 #\2))259(my-check (list-ec (:string c "1" "2" "3") c) => '(#\1 #\2 #\3))260261(my-check (list-ec (:vector x (vector)) x) => '())262(my-check (list-ec (:vector x (vector 1)) x) => '(1))263(my-check (list-ec (:vector x (vector 1 2 3)) x) => '(1 2 3))264(my-check (list-ec (:vector x (vector 1) (vector 2)) x) => '(1 2))265(my-check266 (list-ec (:vector x (vector 1) (vector 2) (vector 3)) x)267 => '(1 2 3))268269(my-check (list-ec (:range x -2) x) => '())270(my-check (list-ec (:range x -1) x) => '())271(my-check (list-ec (:range x 0) x) => '())272(my-check (list-ec (:range x 1) x) => '(0))273(my-check (list-ec (:range x 2) x) => '(0 1))274275(my-check (list-ec (:range x 0 3) x) => '(0 1 2))276(my-check (list-ec (:range x 1 3) x) => '(1 2))277(my-check (list-ec (:range x -2 -1) x) => '(-2))278(my-check (list-ec (:range x -2 -2) x) => '())279280(my-check (list-ec (:range x 1 5 2) x) => '(1 3))281(my-check (list-ec (:range x 1 6 2) x) => '(1 3 5))282(my-check (list-ec (:range x 5 1 -2) x) => '(5 3))283(my-check (list-ec (:range x 6 1 -2) x) => '(6 4 2))284285(my-check (list-ec (:real-range x 0.0 3.0) x) => '(0. 1. 2.))286(my-check (list-ec (:real-range x 0 3.0) x) => '(0. 1. 2.))287(my-check (list-ec (:real-range x 0 3 1.0) x) => '(0. 1. 2.))288289(my-check290 (string-ec (:char-range c #\a #\z) c)291 => "abcdefghijklmnopqrstuvwxyz" )292293(my-check294 (begin295 (let ((f (my-open-output-file "tmp1.out")))296 (do-ec (:range n 10) (begin (write n f) (newline f)))297 (close-output-port f))298 (my-call-with-input-file "tmp1.out"299 (lambda (port) (list-ec (:port x port read) x)) ))300 => (list-ec (:range n 10) n) )301302(my-check303 (begin304 (let ((f (my-open-output-file "tmp1.out")))305 (do-ec (:range n 10) (begin (write n f) (newline f)))306 (close-output-port f))307 (my-call-with-input-file "tmp1.out"308 (lambda (port) (list-ec (:port x port) x)) ))309 => (list-ec (:range n 10) n) )310311312; ==========================================================================313; The special generators :do :let :parallel :while :until314; ==========================================================================315316(my-check (list-ec (:do ((i 0)) (< i 4) ((+ i 1))) i) => '(0 1 2 3))317318(my-check319 (list-ec320 (:do (let ((x 'x)))321 ((i 0))322 (< i 4)323 (let ((j (- 10 i))))324 #t325 ((+ i 1)) )326 j )327 => '(10 9 8 7) )328329(my-check (list-ec (:let x 1) x) => '(1))330(my-check (list-ec (:let x 1) (:let y (+ x 1)) y) => '(2))331(my-check (list-ec (:let x 1) (:let x (+ x 1)) x) => '(2))332333(my-check334 (list-ec (:parallel (:range i 1 10) (:list x '(a b c))) (list i x))335 => '((1 a) (2 b) (3 c)) )336337(my-check338 (list-ec (:while (:range i 1 10) (< i 5)) i)339 => '(1 2 3 4) )340341(my-check342 (list-ec (:until (:range i 1 10) (>= i 5)) i)343 => '(1 2 3 4 5) )344345; with generator that might use inner bindings346347(my-check348 (list-ec (:while (:list i '(1 2 3 4 5 6 7 8 9)) (< i 5)) i)349 => '(1 2 3 4) )350; Was broken in original reference implementation as pointed351; out by sunnan@handgranat.org on 24-Apr-2005 comp.lang.scheme.352; Refer to http://groups-beta.google.com/group/comp.lang.scheme/353; browse_thread/thread/f5333220eaeeed66/75926634cf31c038#75926634cf31c038354355(my-check356 (list-ec (:until (:list i '(1 2 3 4 5 6 7 8 9)) (>= i 5)) i)357 => '(1 2 3 4 5) )358359(my-check360 (list-ec (:while (:vector x (index i) '#(1 2 3 4 5))361 (< x 10))362 x)363 => '(1 2 3 4 5))364; Was broken in reference implementation, even after fix for the365; bug reported by Sunnan, as reported by Jens-Axel Soegaard on366; 4-Jun-2007.367368; combine :while/:until and :parallel369370(my-check371 (list-ec (:while (:parallel (:range i 1 10)372 (:list j '(1 2 3 4 5 6 7 8 9)))373 (< i 5))374 (list i j))375 => '((1 1) (2 2) (3 3) (4 4)))376377(my-check378 (list-ec (:until (:parallel (:range i 1 10)379 (:list j '(1 2 3 4 5 6 7 8 9)))380 (>= i 5))381 (list i j))382 => '((1 1) (2 2) (3 3) (4 4) (5 5)))383384; check that :while/:until really stop the generator385386(my-check387 (let ((n 0))388 (do-ec (:while (:range i 1 10) (begin (set! n (+ n 1)) (< i 5)))389 (if #f #f))390 n)391 => 5)392393(my-check394 (let ((n 0))395 (do-ec (:until (:range i 1 10) (begin (set! n (+ n 1)) (>= i 5)))396 (if #f #f))397 n)398 => 5)399400(my-check401 (let ((n 0))402 (do-ec (:while (:parallel (:range i 1 10)403 (:do () (begin (set! n (+ n 1)) #t) ()))404 (< i 5))405 (if #f #f))406 n)407 => 5)408409(my-check410 (let ((n 0))411 (do-ec (:until (:parallel (:range i 1 10)412 (:do () (begin (set! n (+ n 1)) #t) ()))413 (>= i 5))414 (if #f #f))415 n)416 => 5)417418; ==========================================================================419; The dispatching generator420; ==========================================================================421422(my-check (list-ec (: c '(a b)) c) => '(a b))423(my-check (list-ec (: c '(a b) '(c d)) c) => '(a b c d))424425(my-check (list-ec (: c "ab") c) => '(#\a #\b))426(my-check (list-ec (: c "ab" "cd") c) => '(#\a #\b #\c #\d))427428(my-check (list-ec (: c (vector 'a 'b)) c) => '(a b))429(my-check (list-ec (: c (vector 'a 'b) (vector 'c)) c) => '(a b c))430431(my-check (list-ec (: i 0) i) => '())432(my-check (list-ec (: i 1) i) => '(0))433(my-check (list-ec (: i 10) i) => '(0 1 2 3 4 5 6 7 8 9))434(my-check (list-ec (: i 1 2) i) => '(1))435(my-check (list-ec (: i 1 2 3) i) => '(1))436(my-check (list-ec (: i 1 9 3) i) => '(1 4 7))437438(my-check (list-ec (: i 0.0 1.0 0.2) i) => '(0. 0.2 0.4 0.6 0.8))439440(my-check (list-ec (: c #\a #\c) c) => '(#\a #\b #\c))441442(my-check443 (begin444 (let ((f (my-open-output-file "tmp1.out")))445 (do-ec (:range n 10) (begin (write n f) (newline f)))446 (close-output-port f))447 (my-call-with-input-file "tmp1.out"448 (lambda (port) (list-ec (: x port read) x)) ))449 => (list-ec (:range n 10) n) )450451(my-check452 (begin453 (let ((f (my-open-output-file "tmp1.out")))454 (do-ec (:range n 10) (begin (write n f) (newline f)))455 (close-output-port f))456 (my-call-with-input-file "tmp1.out"457 (lambda (port) (list-ec (: x port) x)) ))458 => (list-ec (:range n 10) n) )459460461; ==========================================================================462; With index variable463; ==========================================================================464465(my-check (list-ec (:list c (index i) '(a b)) (list c i)) => '((a 0) (b 1)))466(my-check (list-ec (:string c (index i) "a") (list c i)) => '((#\a 0)))467(my-check (list-ec (:vector c (index i) (vector 'a)) (list c i)) => '((a 0)))468469(my-check470 (list-ec (:range i (index j) 0 -3 -1) (list i j))471 => '((0 0) (-1 1) (-2 2)) )472473(my-check474 (list-ec (:real-range i (index j) 0 1 0.2) (list i j))475 => '((0. 0) (0.2 1) (0.4 2) (0.6 3) (0.8 4)) )476477(my-check478 (list-ec (:char-range c (index i) #\a #\c) (list c i))479 => '((#\a 0) (#\b 1) (#\c 2)) )480481(my-check482 (list-ec (: x (index i) '(a b c d)) (list x i))483 => '((a 0) (b 1) (c 2) (d 3)) )484485(my-check486 (begin487 (let ((f (my-open-output-file "tmp1.out")))488 (do-ec (:range n 10) (begin (write n f) (newline f)))489 (close-output-port f))490 (my-call-with-input-file "tmp1.out"491 (lambda (port) (list-ec (: x (index i) port) (list x i))) ))492 => '((0 0) (1 1) (2 2) (3 3) (4 4) (5 5) (6 6) (7 7) (8 8) (9 9)) )493494495; ==========================================================================496; The examples from the SRFI document497; ==========================================================================498499; from Abstract500501(my-check (list-ec (: i 5) (* i i)) => '(0 1 4 9 16))502503(my-check504 (list-ec (: n 1 4) (: i n) (list n i))505 => '((1 0) (2 0) (2 1) (3 0) (3 1) (3 2)) )506507; from Generators508509(my-check510 (list-ec (: x (index i) "abc") (list x i))511 => '((#\a 0) (#\b 1) (#\c 2)) )512513(my-check514 (list-ec (:string c (index i) "a" "b") (cons c i))515 => '((#\a . 0) (#\b . 1)) )516517518; ==========================================================================519; Little Shop of Horrors520; ==========================================================================521522(my-check (list-ec (:range x 5) (:range x x) x) => '(0 0 1 0 1 2 0 1 2 3))523524(my-check (list-ec (:list x '(2 "23" (4))) (: y x) y) => '(0 1 #\2 #\3 4))525526(my-check527 (list-ec (:parallel (:integers x)528 (:do ((i 10)) (< x i) ((- i 1))))529 (list x i))530 => '((0 10) (1 9) (2 8) (3 7) (4 6)) )531532533; ==========================================================================534; Less artificial examples535; ==========================================================================536537(define (factorial n) ; n * (n-1) * .. * 1 for n >= 0538 (product-ec (:range k 2 (+ n 1)) k) )539540(my-check (factorial 0) => 1)541(my-check (factorial 1) => 1)542(my-check (factorial 3) => 6)543(my-check (factorial 5) => 120)544545546(define (eratosthenes n) ; primes in {2..n-1} for n >= 1547 (let ((p? (make-string n #\1)))548 (do-ec (:range k 2 n)549 (if (char=? (string-ref p? k) #\1))550 (:range i (* 2 k) n k)551 (string-set! p? i #\0) )552 (list-ec (:range k 2 n) (if (char=? (string-ref p? k) #\1)) k) ))553554(my-check555 (eratosthenes 50)556 => '(2 3 5 7 11 13 17 19 23 29 31 37 41 43 47) )557558(my-check559 (length (eratosthenes 100000))560 => 9592 ) ; we expect 10^5/ln(10^5)561562563(define (pythagoras n) ; a, b, c s.t. 1 <= a <= b <= c <= n, a^2 + b^2 = c^2564 (list-ec565 (:let sqr-n (* n n))566 (:range a 1 (+ n 1))567; (begin (display a) (display " "))568 (:let sqr-a (* a a))569 (:range b a (+ n 1))570 (:let sqr-c (+ sqr-a (* b b)))571 (if (<= sqr-c sqr-n))572 (:range c b (+ n 1))573 (if (= (* c c) sqr-c))574 (list a b c) ))575576(my-check577 (pythagoras 15)578 => '((3 4 5) (5 12 13) (6 8 10) (9 12 15)) )579580(my-check581 (length (pythagoras 200))582 => 127 )583584585(define (qsort xs) ; stable586 (if (null? xs)587 '()588 (let ((pivot (car xs)) (xrest (cdr xs)))589 (append590 (qsort (list-ec (:list x xrest) (if (< x pivot)) x))591 (list pivot)592 (qsort (list-ec (:list x xrest) (if (>= x pivot)) x)) ))))593594(my-check595 (qsort '(1 5 4 2 4 5 3 2 1 3))596 => '(1 1 2 2 3 3 4 4 5 5) )597598599(define (pi-BBP m) ; approx. of pi within 16^-m (Bailey-Borwein-Plouffe)600 (sum-ec601 (:range n 0 (+ m 1))602 (:let n8 (* 8 n))603 (* (- (/ 4 (+ n8 1))604 (+ (/ 2 (+ n8 4))605 (/ 1 (+ n8 5))606 (/ 1 (+ n8 6))))607 (/ 1 (expt 16 n)) )))608609(my-check610 (pi-BBP 5)611 => (/ 40413742330349316707 12864093722915635200) )612613614(define (read-line port) ; next line (incl. #\newline) of port615 (let ((line616 (string-ec617 (:until (:port c port read-char)618 (char=? c #\newline) )619 c )))620 (if (string=? line "")621 (read-char port) ; eof-object622 line )))623624(define (read-lines filename) ; list of all lines625 (my-call-with-input-file626 filename627 (lambda (port)628 (list-ec (:port line port read-line) line) )))629630(my-check631 (begin632 (let ((f (my-open-output-file "tmp1.out")))633 (do-ec (:range n 10) (begin (write n f) (newline f)))634 (close-output-port f))635 (read-lines "tmp1.out") )636 => (list-ec (:char-range c #\0 #\9) (string c #\newline)) )637638639; ==========================================================================640; Summary641; ==========================================================================642643(begin644 (newline)645 (newline)646 (display "correct examples : ")647 (display my-check-correct)648 (newline)649 (display "wrong examples : ")650 (display my-check-wrong)651 (newline)652 (newline) )653654(exit my-check-wrong)