Here's another code pair, in this case, SRFI-6. SRFI-6 and SRFI-9 are two of the most-implemented SRFIs, so I figured that'd be a reasonable place to start. I decided to use the ". <* ... *>" construct, and restart indenting. It might not really be long enough to justify that, but if nothing else, it shows off what it looks like (I think it looks fine). --- David A. Wheeler ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; As s-expressions ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; This code is from SRFI-6 by William D Clinger ; http://srfi.schemers.org/srfi-6/srfi-6.html ; What follows is just an outline of how these procedures might be ; implemented, because a real implementation would also have to redefine ; READ, WRITE, and so forth to use PEEK-CHAR, READ-CHAR, and WRITE-CHAR ; as redefined below. ; Since the code for READ and WRITE would be identical to code that already ; exists in any implementation, however, it should not be necessary for ; this SRFI to include that code within this SRFI. Including it would only ; detract from the readability of this implementation. ; This implementation is not IEEE- or R5RS-compliant, ; for the following reasons: ; ; This implementation does not redefine procedures ; like READ, WRITE, DISPLAY, and NEWLINE to ensure ; that they use the redefined PEEK-CHAR, READ-CHAR, ; WRITE-CHAR, and so forth. That should be easy ; for an implementor to do, however. ; ; This implementation obtains an end-of-file object ; by reading a Unix-specific file, /dev/null. (define open-input-string 0) ; assigned below (define open-output-string 0) ; assigned below (define get-output-string 0) ; assigned below ; We have to remember the original procedures before ; we can define new ones. (define ur-vector? vector?) (define ur-vector-length vector-length) (define ur-vector-ref vector-ref) (define ur-vector-set! vector-set!) (define ur-input-port? input-port?) (define ur-output-port? output-port?) (define ur-close-input-port close-input-port) (define ur-close-output-port close-output-port) (define ur-peek-char peek-char) (define ur-read-char read-char) (define ur-write-char write-char) ; IEEE/ANSI Scheme insists that we define any global ; variables that we are going to assign. R5RS Scheme ; apparently does not require this. (define vector? vector?) (define vector-length vector-length) (define vector-ref vector-ref) (define vector-set! vector-set!) (define input-port? input-port?) (define output-port? output-port?) (define close-input-port close-input-port) (define close-output-port close-output-port) (define peek-char peek-char) (define read-char read-char) (define write-char write-char) (let ((ur-vector? ur-vector?) (ur-vector-length ur-vector-length) (ur-vector-ref ur-vector-ref) (ur-vector-set! ur-vector-set!) (ur-input-port? ur-input-port?) (ur-output-port? ur-output-port?) (ur-close-input-port ur-close-input-port) (ur-close-output-port ur-close-output-port) (ur-peek-char ur-peek-char) (ur-read-char ur-read-char) (ur-write-char ur-write-char) (eof (call-with-input-file "/dev/null" read-char)) (input-string-tag (list 'input-string-tag)) (output-string-tag (list 'output-string-tag))) (define (error) (display "You're not supposed to do that!") (newline) (if #f #f)) (define (restrict f pred?) (lambda (x . rest) (if (pred? x) (apply f x rest) (error)))) (define (my-vector? x) (and (ur-vector? x) (not (input-string? x)) (not (output-string? x)))) (define (input-string? x) (and (ur-vector? x) (positive? (ur-vector-length x)) (eq? input-string-tag (ur-vector-ref x 0)))) (define (output-string? x) (and (ur-vector? x) (positive? (ur-vector-length x)) (eq? output-string-tag (ur-vector-ref x 0)))) (define (selector pred? i) (lambda (x) (if (pred? x) (ur-vector-ref x i) (error)))) (define (setter pred? i) (lambda (x y) (if (pred? x) (begin (ur-vector-set! x i y) (if #f #f)) (error)))) (set! vector? my-vector?) (set! vector-length (restrict ur-vector-length my-vector?)) (set! vector-ref (restrict ur-vector-ref my-vector?)) (set! vector-set! (restrict ur-vector-set! my-vector?)) (let () ; The guts of the implementation begin here. (define (make-input-string s) (vector input-string-tag #t s (string-length s) 0)) (define input-string:open? (selector input-string? 1)) (define input-string:open?! (setter input-string? 1)) (define input-string:string (selector input-string? 2)) (define input-string:size (selector input-string? 3)) (define input-string:next (selector input-string? 4)) (define input-string:next! (setter input-string? 4)) (define (make-output-string) (vector output-string-tag #t '())) (define output-string:open? (selector output-string? 1)) (define output-string:open?! (setter output-string? 1)) (define output-string:contents (selector output-string? 2)) (define output-string:contents! (setter output-string? 2)) (set! open-input-string make-input-string) (set! open-output-string make-output-string) (set! get-output-string (lambda (x) (list->string (reverse (output-string:contents x))))) (set! input-port? (lambda (x) (or (ur-input-port? x) (input-string? x)))) (set! output-port? (lambda (x) (or (ur-output-port? x) (output-string? x)))) (set! close-input-port (lambda (x) (if (input-string? x) (input-string:open?! x #f) (ur-close-input-port x)))) (set! close-output-port (lambda (x) (if (output-string? x) (output-string:open?! x #f) (ur-close-output-port x)))) (set! peek-char (lambda args (if (null? args) (ur-peek-char) (let ((x (car args))) (if (input-string? x) (let ((s (input-string:string x)) (i (input-string:next x)) (n (input-string:size x))) (if (input-string:open? x) (if (< i n) (string-ref s i) eof) (error))) (ur-peek-char x)))))) (set! read-char (lambda args (if (null? args) (ur-read-char) (let ((x (car args))) (if (input-string? x) (let ((s (input-string:string x)) (i (input-string:next x)) (n (input-string:size x))) (if (input-string:open? x) (if (< i n) (let ((c (string-ref s i))) (input-string:next! x (+ i 1)) c) eof) (error))) (ur-read-char x)))))) (set! write-char (lambda (c . rest) (if (null? rest) (ur-write-char c) (let ((x (car rest))) (if (output-string? x) (if (output-string:open? x) (output-string:contents! x (cons c (output-string:contents x))) (error)) (ur-write-char c x)))))) (if #f #f))) ; Copyright ; Copyright (C) William D Clinger (1999). All Rights Reserved. ; Permission is hereby granted, free of charge, to any person obtaining a ; copy of this software and associated documentation files (the "Software"), ; to deal in the Software without restriction, including without limitation ; the rights to use, copy, modify, merge, publish, distribute, sublicense, ; and/or sell copies of the Software, and to permit persons to whom the ; Software is furnished to do so, subject to the following conditions: ; The above copyright notice and this permission notice shall be included ; in all copies or substantial portions of the Software. ; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ; IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ; FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ; THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR ; OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ; ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR ; OTHER DEALINGS IN THE SOFTWARE. ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; As sweet-expressions ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ; This code is from SRFI-6 by William D Clinger ; http://srfi.schemers.org/srfi-6/srfi-6.html ; What follows is just an outline of how these procedures might be ; implemented, because a real implementation would also have to redefine ; READ, WRITE, and so forth to use PEEK-CHAR, READ-CHAR, and WRITE-CHAR ; as redefined below. ; Since the code for READ and WRITE would be identical to code that already ; exists in any implementation, however, it should not be necessary for ; this SRFI to include that code within this SRFI. Including it would only ; detract from the readability of this implementation. ; This implementation is not IEEE- or R5RS-compliant, ; for the following reasons: ; ; This implementation does not redefine procedures ; like READ, WRITE, DISPLAY, and NEWLINE to ensure ; that they use the redefined PEEK-CHAR, READ-CHAR, ; WRITE-CHAR, and so forth. That should be easy ; for an implementor to do, however. ; ; This implementation obtains an end-of-file object ; by reading a Unix-specific file, /dev/null. define open-input-string 0 ; assigned below define open-output-string 0 ; assigned below define get-output-string 0 ; assigned below ; We have to remember the original procedures before ; we can define new ones. define ur-vector? vector? define ur-vector-length vector-length define ur-vector-ref vector-ref define ur-vector-set! vector-set! define ur-input-port? input-port? define ur-output-port? output-port? define ur-close-input-port close-input-port define ur-close-output-port close-output-port define ur-peek-char peek-char define ur-read-char read-char define ur-write-char write-char ; IEEE/ANSI Scheme insists that we define any global ; variables that we are going to assign. R5RS Scheme ; apparently does not require this. define vector? vector? define vector-length vector-length define vector-ref vector-ref define vector-set! vector-set! define input-port? input-port? define output-port? output-port? define close-input-port close-input-port define close-output-port close-output-port define peek-char peek-char define read-char read-char define write-char write-char let ! \\ ! ur-vector? ur-vector? ! ur-vector-length ur-vector-length ! ur-vector-ref ur-vector-ref ! ur-vector-set! ur-vector-set! ! ur-input-port? ur-input-port? ! ur-output-port? ur-output-port? ! ur-close-input-port ur-close-input-port ! ur-close-output-port ur-close-output-port ! ur-peek-char ur-peek-char ! ur-read-char ur-read-char ! ur-write-char ur-write-char ! eof call-with-input-file("/dev/null" read-char) ! input-string-tag list('input-string-tag) ! output-string-tag list('output-string-tag) ! define error() ! display "You're not supposed to do that!" ! newline() ! if #f #f ! define restrict(f pred?) ! lambda x(. rest) ! if pred?(x) apply(f x rest) error() ! define my-vector?(x) ! and ! ur-vector? x ! not input-string?(x) ! not output-string?(x) ! define input-string?(x) ! and ! ur-vector? x ! positive? ur-vector-length(x) ! eq? input-string-tag ur-vector-ref(x 0) ! define output-string?(x) ! and ! ur-vector? x ! positive? ur-vector-length(x) ! eq? output-string-tag ur-vector-ref(x 0) ! define selector(pred? i) ! lambda x() ! if pred?(x) ur-vector-ref(x i) error() ! define setter(pred? i) ! lambda x(y) ! if pred?(x) ! begin ur-vector-set!(x i y) if(#f #f) ! error() ! set! vector? my-vector? ! set! vector-length restrict(ur-vector-length my-vector?) ! set! vector-ref restrict(ur-vector-ref my-vector?) ! set! vector-set! restrict(ur-vector-set! my-vector?) ! let () . <* ; The guts of the implementation begin here. define make-input-string(s) ! vector input-string-tag #t s string-length(s) 0 define input-string:open? selector(input-string? 1) define input-string:open?! setter(input-string? 1) define input-string:string selector(input-string? 2) define input-string:size selector(input-string? 3) define input-string:next selector(input-string? 4) define input-string:next! setter(input-string? 4) define make-output-string() ! vector output-string-tag #t '() define output-string:open? selector(output-string? 1) define output-string:open?! setter(output-string? 1) define output-string:contents selector(output-string? 2) define output-string:contents! setter(output-string? 2) set! open-input-string make-input-string set! open-output-string make-output-string set! get-output-string ! lambda x() ! list->string reverse(output-string:contents(x)) set! input-port? ! lambda x() {ur-input-port?(x) or input-string?(x)} set! output-port? ! lambda x() {ur-output-port?(x) or output-string?(x)} set! close-input-port ! lambda x() ! if input-string?(x) ! input-string:open?! x #f ! ur-close-input-port x set! close-output-port ! lambda x() ! if output-string?(x) ! output-string:open?! x #f ! ur-close-output-port x set! peek-char ! lambda args ! if null?(args) ! ur-peek-char() ! let <* x car(args) *> ! if input-string?(x) ! ! let ! ! \\ ! ! s input-string:string(x) ! ! i input-string:next(x) ! ! n input-string:size(x) ! ! if input-string:open?(x) ! ! if {i < n} string-ref(s i) eof ! ! error() ! ! ur-peek-char x set! read-char ! lambda args ! if null?(args) ! ur-read-char() ! let <* x car(args) *> ! if input-string?(x) ! let ! \\ ! s input-string:string(x) ! i input-string:next(x) ! n input-string:size(x) ! if input-string:open?(x) ! if {i < n} ! ! let <* c $ string-ref s i *> ! ! input-string:next! x {i + 1} ! ! c ! ! eof ! error() ! ur-read-char x set! write-char ! lambda c(. rest) ! if null?(rest) ! ! ur-write-char c ! ! let <* x car(rest) *> ! ! if output-string?(x) ! ! ! if output-string:open?(x) ! ! ! output-string:contents! x cons(c output-string:contents(x)) ! ! ! error() ! ! ! ur-write-char c x if #f #f *> ; Copyright ; Copyright (C) William D Clinger (1999). All Rights Reserved. ; Permission is hereby granted, free of charge, to any person obtaining a ; copy of this software and associated documentation files (the "Software"), ; to deal in the Software without restriction, including without limitation ; the rights to use, copy, modify, merge, publish, distribute, sublicense, ; and/or sell copies of the Software, and to permit persons to whom the ; Software is furnished to do so, subject to the following conditions: ; The above copyright notice and this permission notice shall be included ; in all copies or substantial portions of the Software. ; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ; IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ; FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL ; THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR ; OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ; ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR ; OTHER DEALINGS IN THE SOFTWARE.