~ chicken-core (chicken-5) /tests/r5rs_pitfalls.scm
Trap1;; r5rs_pitfalls.scm2;;3;; This program attempts to test a Scheme implementation's conformance4;; to various subtle edge-cases and consequences of the R5RS Scheme standard.5;; Code was collected from public forums, and is hereby placed in the public domain.6;;7;;8(define-syntax should-be9 (syntax-rules ()10 ((_ test-id value expression)11 (let ((return-value expression))12 (if (not (equal? return-value value))13 (for-each (lambda (v) (display v))14 `("Failure: " test-id ", expected '"15 value "', got '" ,return-value "'." #\newline))16 (for-each (lambda (v) (display v))17 '("Passed: " test-id #\newline)))))))1819(define call/cc call-with-current-continuation)2021;; Section 1: Proper letrec implementation2223;;Credits to Al Petrofsky24;; In thread:25;; defines in letrec body26;; http://groups.google.com/groups?selm=87bsoq0wfk.fsf%40app.dial.idiom.com27(should-be 1.1 028 (let ((cont #f))29 (letrec ((x (call-with-current-continuation (lambda (c) (set! cont c) 0)))30 (y (call-with-current-continuation (lambda (c) (set! cont c) 0))))31 (if cont32 (let ((c cont))33 (set! cont #f)34 (set! x 1)35 (set! y 1)36 (c 0))37 (+ x y)))))3839;;Credits to Al Petrofsky40;; In thread:41;; Widespread bug (arguably) in letrec when an initializer returns twice42;; http://groups.google.com/groups?selm=87d793aacz.fsf_-_%40app.dial.idiom.com43(should-be 1.2 #t44 (letrec ((x (call/cc list)) (y (call/cc list)))45 (cond ((procedure? x) (x (pair? y)))46 ((procedure? y) (y (pair? x))))47 (let ((x (car x)) (y (car y)))48 (and (call/cc x) (call/cc y) (call/cc x)))))4950;;Credits to Alan Bawden51;; In thread:52;; LETREC + CALL/CC = SET! even in a limited setting53;; http://groups.google.com/groups?selm=19890302162742.4.ALAN%40PIGPEN.AI.MIT.EDU54(should-be 1.3 #t55 (letrec ((x (call-with-current-continuation56 (lambda (c)57 (list #T c)))))58 (if (car x)59 ((cadr x) (list #F (lambda () x)))60 (eq? x ((cadr x))))))6162;; Section 2: Proper call/cc and procedure application6364;;Credits to Al Petrofsky, (and a wink to Matthias Blume)65;; In thread:66;; Widespread bug in handling (call/cc (lambda (c) (0 (c 1)))) => 167;; http://groups.google.com/groups?selm=87g00y4b6l.fsf%40radish.petrofsky.org68(should-be 2.1 169 (call/cc (lambda (c) (0 (c 1)))))7071;; Section 3: Hygienic macros7273;; Eli Barzilay74;; In thread:75;; R5RS macros...76;; http://groups.google.com/groups?selm=skitsdqjq3.fsf%40tulare.cs.cornell.edu77(should-be 3.1 478 (let-syntax ((foo79 (syntax-rules ()80 ((_ expr) (+ expr 1)))))81 (let ((+ *))82 (foo 3))))838485;; Al Petrofsky again86;; In thread:87;; Buggy use of begin in r5rs cond and case macros.88;; http://groups.google.com/groups?selm=87bse3bznr.fsf%40radish.petrofsky.org89(should-be 3.2 290 (let-syntax ((foo (syntax-rules ()91 ((_ var) (define var 1)))))92 (let ((x 2))93 (begin (define foo +))94 (cond (else (foo x)))95 x)))9697;;Al Petrofsky98;; In thread:99;; An Advanced syntax-rules Primer for the Mildly Insane100;; http://groups.google.com/groups?selm=87it8db0um.fsf@radish.petrofsky.org101102(should-be 3.3 1103 (let ((x 1))104 (let-syntax105 ((foo (syntax-rules ()106 ((_ y) (let-syntax107 ((bar (syntax-rules ()108 ((_) (let ((x 2)) y)))))109 (bar))))))110 (foo x))))111112;; Al Petrofsky113;; Contributed directly114(should-be 3.4 1115 (let-syntax ((x (syntax-rules ()))) 1))116117;; Setion 4: No identifiers are reserved118119;;(Brian M. Moore)120;; In thread:121;; shadowing syntatic keywords, bug in MIT Scheme?122;; http://groups.google.com/groups?selm=6e6n88%248qf%241%40news.cc.ukans.edu123(should-be 4.1 '(x)124 ((lambda lambda lambda) 'x))125126(should-be 4.2 '(1 2 3)127 ((lambda (begin) (begin 1 2 3)) (lambda lambda lambda)))128129(should-be 4.3 #f130 (let ((quote -)) (eqv? '1 1)))131;; Section 5: #f/() distinctness132133;; Scott Miller134(should-be 5.1 #f135 (eq? #f '()))136(should-be 5.2 #f137 (eqv? #f '()))138(should-be 5.3 #f139 (equal? #f '()))140141;; Section 6: string->symbol case sensitivity142143;; Jens Axel S?gaard144;; In thread:145;; Symbols in DrScheme - bug?146;; http://groups.google.com/groups?selm=3be55b4f%240%24358%24edfadb0f%40dspool01.news.tele.dk147(should-be 6.1 #f148 (eq? (string->symbol "f") (string->symbol "F")))149150;; Section 7: First class continuations151152;; Scott Miller153;; No newsgroup posting associated. The gist of this test and 7.2154;; is that once captured, a continuation should be unmodified by the155;; invocation of other continuations. This test determines that this is156;; the case by capturing a continuation and setting it aside in a temporary157;; variable while it invokes that and another continuation, trying to158;; side effect the first continuation. This test case was developed when159;; testing SISC 1.7's lazy CallFrame unzipping code.160(define r #f)161(define a #f)162(define b #f)163(define c #f)164(define i 0)165(should-be 7.1 28166 (let ()167 (set! r (+ 1 (+ 2 (+ 3 (call/cc (lambda (k) (set! a k) 4))))168 (+ 5 (+ 6 (call/cc (lambda (k) (set! b k) 7))))))169 (if (not c)170 (set! c a))171 (set! i (+ i 1))172 (case i173 ((1) (a 5))174 ((2) (b 8))175 ((3) (a 6))176 ((4) (c 4)))177 r))178179;; Same test, but in reverse order180(define r #f)181(define a #f)182(define b #f)183(define c #f)184(define i 0)185(should-be 7.2 28186 (let ()187 (set! r (+ 1 (+ 2 (+ 3 (call/cc (lambda (k) (set! a k) 4))))188 (+ 5 (+ 6 (call/cc (lambda (k) (set! b k) 7))))))189 (if (not c)190 (set! c a))191 (set! i (+ i 1))192 (case i193 ((1) (b 8))194 ((2) (a 5))195 ((3) (b 7))196 ((4) (c 4)))197 r))198199;; Credits to Matthias Radestock200;; Another test case used to test SISC's lazy CallFrame routines.201(should-be 7.3 '((-1 4 5 3)202 (4 -1 5 3)203 (-1 5 4 3)204 (5 -1 4 3)205 (4 5 -1 3)206 (5 4 -1 3))207 (let ((k1 #f)208 (k2 #f)209 (k3 #f)210 (state 0))211 (define (identity x) x)212 (define (fn)213 ((identity (if (= state 0)214 (call/cc (lambda (k) (set! k1 k) +))215 +))216 (identity (if (= state 0)217 (call/cc (lambda (k) (set! k2 k) 1))218 1))219 (identity (if (= state 0)220 (call/cc (lambda (k) (set! k3 k) 2))221 2))))222 (define (check states)223 (set! state 0)224 (let* ((res '())225 (r (fn)))226 (set! res (cons r res))227 (if (null? states)228 res229 (begin (set! state (car states))230 (set! states (cdr states))231 (case state232 ((1) (k3 4))233 ((2) (k2 2))234 ((3) (k1 -)))))))235 (map check '((1 2 3) (1 3 2) (2 1 3) (2 3 1) (3 1 2) (3 2 1)))))236237;; Modification of the yin-yang puzzle so that it terminates and produces238;; a value as a result. (Scott G. Miller)239(should-be 7.4 '(10 9 8 7 6 5 4 3 2 1 0)240 (let ((x '())241 (y 0))242 (call/cc243 (lambda (escape)244 (let* ((yin ((lambda (foo)245 (set! x (cons y x))246 (if (= y 10)247 (escape x)248 (begin249 (set! y 0)250 foo)))251 (call/cc (lambda (bar) bar))))252 (yang ((lambda (foo)253 (set! y (+ y 1))254 foo)255 (call/cc (lambda (baz) baz)))))256 (yin yang))))))257258;; Miscellaneous259260;;Al Petrofsky261;; In thread:262;; R5RS Implementors Pitfalls263;; http://groups.google.com/groups?selm=871zemtmd4.fsf@app.dial.idiom.com264(should-be 8.1 -1265 (let - ((n (- 1))) n))266267(should-be 8.2 '(1 2 3 4 1 2 3 4 5)268 (let ((ls (list 1 2 3 4)))269 (append ls ls '(5))))270271;; This example actually illustrates a bug in R5RS. If a Scheme system272;; follows the letter of the standard, 1 should be returned, but273;; the general agreement is that 2 should instead be returned.274;; The reason is that in R5RS, let-syntax always introduces new scope, thus275;; in the following test, the let-syntax breaks the definition section276;; and begins the expression section of the let.277;;278;; The general agreement by the implementors in 1998 was that the following279;; should be possible, but isn't:280;;281;; (define ---)282;; (let-syntax (---)283;; (define ---)284;; (define ---))285;; (define ---)286;;287;; Scheme systems based on the Portable syntax-case expander by Dybvig288;; and Waddell do allow the above, and thus often violate the letter of289;; R5RS. In such systems, the following will produce a local scope:290;;291;; (define ---)292;; (let-syntax ((a ---))293;; (let ()294;; (define ---)295;; (define ---)))296;; (define ---)297;;298;; Credits to Matthias Radestock and thanks to R. Kent Dybvig for the299;; explanation and background300(should-be 8.3 1301 (let ((x 1))302 (let-syntax ((foo (syntax-rules () ((_) 2))))303 (define x (foo))304 3)305 x))306307;;Not really an error to fail this (Matthias Radestock)308;;If this returns (0 1 0), your map isn't call/cc safe, but is probably309;;tail-recursive. If its (0 0 0), the opposite is true.310(let ((result311 (let ()312 (define executed-k #f)313 (define cont #f)314 (define res1 #f)315 (define res2 #f)316 (set! res1 (map (lambda (x)317 (if (= x 0)318 (call/cc (lambda (k) (set! cont k) 0))319 0))320 '(1 0 2)))321 (if (not executed-k)322 (begin (set! executed-k #t)323 (set! res2 res1)324 (cont 1)))325 res2)))326 (if (equal? result '(0 0 0))327 (display "Map is call/cc safe, but probably not tail recursive or inefficient.")328 (display "Map is not call/cc safe, but probably tail recursive and efficient."))329 (newline))330