Merge remote branch 'origin/master' into samth/new-logic2

Conflicts:
	collects/tests/typed-scheme/unit-tests/typecheck-tests.rkt
This commit is contained in:
Sam Tobin-Hochstadt 2010-04-30 13:48:49 -04:00
commit 5e9ae84b15
224 changed files with 1810 additions and 1733 deletions

View File

@ -1,6 +1,6 @@
#lang scheme/load #lang scheme/load
(require rktunit) (require racunit)
(require 2htdp/batch-io) (require 2htdp/batch-io)
(define file "batch-io.txt") (define file "batch-io.txt")

View File

@ -45,7 +45,7 @@
scheme/math scheme/math
scheme/class scheme/class
scheme/gui/base scheme/gui/base
rktunit racunit
(prefix-in 1: htdp/image) (prefix-in 1: htdp/image)
(only-in lang/htdp-advanced equal~?)) (only-in lang/htdp-advanced equal~?))

View File

@ -662,7 +662,7 @@ mz-extras :+= (- (package: "unstable")
;; -------------------- plai ;; -------------------- plai
plt-extras :+= (package: "plai/") plt-extras :+= (package: "plai/")
plt-extras :+= (package: "rktunit/") plt-extras :+= (package: "racunit/")
plt-extras :+= (package: "schemeunit/") plt-extras :+= (package: "schemeunit/")
;; ============================================================================ ;; ============================================================================

View File

@ -615,26 +615,26 @@
("schematics" "port.plt" 1 0 #f) ("schematics" "port.plt" 1 0 #f)
("schematics" "random.plt" 1 0 #f) ("schematics" "random.plt" 1 0 #f)
("schematics" "sake.plt" 1 0 "4.0") ("schematics" "sake.plt" 1 0 "4.0")
("schematics" "rktunit.plt" 3 4 "4.0") ("schematics" "racunit.plt" 3 4 "4.0")
("schematics" "rktunit.plt" 3 3 "4.0") ("schematics" "racunit.plt" 3 3 "4.0")
("schematics" "rktunit.plt" 3 2 "4.0") ("schematics" "racunit.plt" 3 2 "4.0")
("schematics" "rktunit.plt" 3 1 "4.0") ("schematics" "racunit.plt" 3 1 "4.0")
("schematics" "rktunit.plt" 3 0 "4.0") ("schematics" "racunit.plt" 3 0 "4.0")
("schematics" "rktunit.plt" 2 11 "4.1.0.3") ("schematics" "racunit.plt" 2 11 "4.1.0.3")
("schematics" "rktunit.plt" 2 10 "369.1") ("schematics" "racunit.plt" 2 10 "369.1")
("schematics" "rktunit.plt" 2 9 "369.1") ("schematics" "racunit.plt" 2 9 "369.1")
("schematics" "rktunit.plt" 2 8 "369.1") ("schematics" "racunit.plt" 2 8 "369.1")
("schematics" "rktunit.plt" 2 7 "369.1") ("schematics" "racunit.plt" 2 7 "369.1")
("schematics" "rktunit.plt" 2 6 "369.1") ("schematics" "racunit.plt" 2 6 "369.1")
("schematics" "rktunit.plt" 2 5 "369.1") ("schematics" "racunit.plt" 2 5 "369.1")
("schematics" "rktunit.plt" 2 4 "369.1") ("schematics" "racunit.plt" 2 4 "369.1")
("schematics" "rktunit.plt" 2 3 #f) ("schematics" "racunit.plt" 2 3 #f)
("schematics" "rktunit.plt" 2 2 #f) ("schematics" "racunit.plt" 2 2 #f)
("schematics" "rktunit.plt" 2 1 #f) ("schematics" "racunit.plt" 2 1 #f)
("schematics" "rktunit.plt" 2 0 #f) ("schematics" "racunit.plt" 2 0 #f)
("schematics" "rktunit.plt" 1 2 #f) ("schematics" "racunit.plt" 1 2 #f)
("schematics" "rktunit.plt" 1 1 #f) ("schematics" "racunit.plt" 1 1 #f)
("schematics" "rktunit.plt" 1 0 #f) ("schematics" "racunit.plt" 1 0 #f)
("schematics" "si.plt" 1 0 #f) ("schematics" "si.plt" 1 0 #f)
("schematics" "spgsql.plt" 2 3 "371.3") ("schematics" "spgsql.plt" 2 3 "371.3")
("schematics" "spgsql.plt" 2 2 "371.3") ("schematics" "spgsql.plt" 2 2 "371.3")

View File

@ -1127,17 +1127,18 @@ path/s is either such a string or a list of them.
"collects/scheme/gui.rkt" drdr:command-line "mred-text -t ~s" "collects/scheme/gui.rkt" drdr:command-line "mred-text -t ~s"
"collects/scheme/match" responsible (samth) "collects/scheme/match" responsible (samth)
"collects/scheme/match.rkt" responsible (samth) "collects/scheme/match.rkt" responsible (samth)
"collects/rktunit" responsible (jay noel ryanc) "collects/racunit" responsible (jay noel ryanc)
"collects/schemeunit" responsible (jay) "collects/schemeunit" responsible (jay)
"collects/rktunit/gui.rkt" responsible (ryanc) drdr:command-line "mred-text -t ~s" "collects/schemeunit/gui.rkt" responsible (jay) drdr:command-line "mred-text -t ~s"
"collects/rktunit/private/gui" responsible (ryanc) "collects/racunit/gui.rkt" responsible (ryanc) drdr:command-line "mred-text -t ~s"
"collects/rktunit/private/gui/config.rkt" drdr:command-line "mred-text -t ~s" "collects/racunit/private/gui" responsible (ryanc)
"collects/rktunit/private/gui/controller.rkt" drdr:command-line "mred-text -t ~s" "collects/racunit/private/gui/config.rkt" drdr:command-line "mred-text -t ~s"
"collects/rktunit/private/gui/gui.rkt" drdr:command-line "mred-text -t ~s" "collects/racunit/private/gui/controller.rkt" drdr:command-line "mred-text -t ~s"
"collects/rktunit/private/gui/model2rml.rkt" drdr:command-line "mred-text -t ~s" "collects/racunit/private/gui/gui.rkt" drdr:command-line "mred-text -t ~s"
"collects/rktunit/private/gui/rml.rkt" drdr:command-line "mred-text -t ~s" "collects/racunit/private/gui/model2rml.rkt" drdr:command-line "mred-text -t ~s"
"collects/rktunit/private/gui/view.rkt" drdr:command-line "mred-text -t ~s" "collects/racunit/private/gui/rml.rkt" drdr:command-line "mred-text -t ~s"
"collects/rktunit/tool.rkt" responsible (ryanc) drdr:command-line "mred-text -t ~s" "collects/racunit/private/gui/view.rkt" drdr:command-line "mred-text -t ~s"
"collects/racunit/tool.rkt" responsible (ryanc) drdr:command-line "mred-text -t ~s"
"collects/scribble/run.rkt" drdr:command-line "mzc ~s" "collects/scribble/run.rkt" drdr:command-line "mzc ~s"
"collects/scribble/tools/drscheme-buttons.rkt" drdr:command-line "mred-text ~s" "collects/scribble/tools/drscheme-buttons.rkt" drdr:command-line "mred-text ~s"
"collects/scribble/tools/private/mk-drs-bitmaps.rkt" drdr:command-line "mred-text ~s" drdr:timeout 240 "collects/scribble/tools/private/mk-drs-bitmaps.rkt" drdr:command-line "mred-text ~s" drdr:timeout 240
@ -1584,7 +1585,7 @@ path/s is either such a string or a list of them.
"collects/tests/planet/examples/dummy-module.rkt" drdr:command-line "" "collects/tests/planet/examples/dummy-module.rkt" drdr:command-line ""
"collects/tests/plot/run-tests.rkt" drdr:command-line "mred-text -t ~s" "collects/tests/plot/run-tests.rkt" drdr:command-line "mred-text -t ~s"
"collects/tests/run-automated-tests.rkt" drdr:command-line "mzc -k ~s" drdr:timeout 600 "collects/tests/run-automated-tests.rkt" drdr:command-line "mzc -k ~s" drdr:timeout 600
"collects/tests/rktunit" responsible (jay noel) "collects/tests/racunit" responsible (jay noel)
"collects/tests/srfi/1/run-tests.rkt" drdr:command-line "mzscheme -f ~s" "collects/tests/srfi/1/run-tests.rkt" drdr:command-line "mzscheme -f ~s"
"collects/tests/srfi/40/run-tests.rkt" drdr:command-line "mzscheme -f ~s" "collects/tests/srfi/40/run-tests.rkt" drdr:command-line "mzscheme -f ~s"
"collects/tests/srfi/43/run-tests.rkt" drdr:command-line "mzscheme -f ~s" "collects/tests/srfi/43/run-tests.rkt" drdr:command-line "mzscheme -f ~s"

View File

@ -1,7 +1,7 @@
#lang scheme/base #lang scheme/base
(require (for-syntax scheme/base) (require (for-syntax scheme/base)
"../lex.ss" "../lex.ss"
rktunit) racunit)
(define-syntax (catch-syn-error stx) (define-syntax (catch-syn-error stx)
(syntax-case stx () (syntax-case stx ()

View File

@ -22,7 +22,7 @@
(unpack-blame pos) (unpack-blame pos)
"<<unknown party>>" "<<unknown party>>"
#t #t
name) "<<unknown party>>")
x x
fmt fmt
args)) args))
@ -60,7 +60,7 @@
(unpack-blame (if original? pos neg)) (unpack-blame (if original? pos neg))
(unpack-blame (if original? neg pos)) (unpack-blame (if original? neg pos))
original? original?
name))))) (unpack-blame (if original? neg pos)))))))
(define (legacy-property name) (define (legacy-property name)
(define-values [ prop pred get ] (define-values [ prop pred get ]

View File

@ -5,13 +5,15 @@
racket/struct-info)) racket/struct-info))
(provide (all-from-out "private/serialize.ss") (provide (all-from-out "private/serialize.ss")
serializable-struct
serializable-struct/versions
define-serializable-struct define-serializable-struct
define-serializable-struct/versions) define-serializable-struct/versions)
(define-syntax (define-serializable-struct/versions/derived stx) (define-syntax (define-serializable-struct/versions/derived stx)
(syntax-case stx () (syntax-case stx ()
;; First check `id/sup': ;; First check `id/sup':
[(_ orig-stx id/sup . _) [(_ orig-stx make-prefix? id/sup . _)
(not (or (identifier? #'id/sup) (not (or (identifier? #'id/sup)
(syntax-case #'id/sup () (syntax-case #'id/sup ()
[(id sup) (and (identifier? #'id) [(id sup) (and (identifier? #'id)
@ -22,11 +24,11 @@
;; Not valid, so let `define-struct/derived' complain: ;; Not valid, so let `define-struct/derived' complain:
#'(define-struct/derived orig-stx id/sup ())] #'(define-struct/derived orig-stx id/sup ())]
;; Check version: ;; Check version:
[(_ orig-stx id/sup vers . _) [(_ orig-stx make-prefix? id/sup vers . _)
(not (exact-nonnegative-integer? (syntax-e #'vers))) (not (exact-nonnegative-integer? (syntax-e #'vers)))
(raise-syntax-error #f "expected a nonnegative exact integer for a version" #'orig-stx #'vers)] (raise-syntax-error #f "expected a nonnegative exact integer for a version" #'orig-stx #'vers)]
;; Main case: ;; Main case:
[(_ orig-stx id/sup vers (field ...) ([other-vers make-proc-expr cycle-make-proc-expr] ...) [(_ orig-stx make-prefix? id/sup vers (field ...) ([other-vers make-proc-expr cycle-make-proc-expr] ...)
prop ...) prop ...)
(let* ([id (if (identifier? #'id/sup) (let* ([id (if (identifier? #'id/sup)
#'id/sup #'id/sup
@ -35,10 +37,22 @@
#f #f
(extract-struct-info (syntax-local-value (cadr (syntax->list #'id/sup)))))] (extract-struct-info (syntax-local-value (cadr (syntax->list #'id/sup)))))]
[fields (syntax->list #'(field ...))] [fields (syntax->list #'(field ...))]
[maker (datum->syntax id [given-maker (let loop ([props (syntax->list #'(prop ...))])
(string->symbol (cond
(format "make-~a" (syntax-e id))) [(null? props) #f]
id)] [(null? (cdr props)) #f]
[(or (eq? (syntax-e (car props)) '#:constructor-name)
(eq? (syntax-e (car props)) '#:extra-constructor-name))
(and (identifier? (cadr props))
(cadr props))]
[else (loop (cdr props))]))]
[maker (or given-maker
(if (syntax-e #'make-prefix?)
(datum->syntax id
(string->symbol
(format "make-~a" (syntax-e id)))
id)
id))]
[getters (map (lambda (field) [getters (map (lambda (field)
(datum->syntax (datum->syntax
id id
@ -103,6 +117,10 @@
id/sup id/sup
(field ...) (field ...)
prop ... prop ...
#,@(if (or given-maker
(syntax-e #'make-prefix?))
null
(list #'#:constructor-name id))
#:property prop:serializable #:property prop:serializable
(make-serialize-info (make-serialize-info
;; The struct-to-vector function: -------------------- ;; The struct-to-vector function: --------------------
@ -203,14 +221,38 @@
(define-syntax (define-serializable-struct/versions stx) (define-syntax (define-serializable-struct/versions stx)
(syntax-case stx () (syntax-case stx ()
[(_ . rest) [(_ . rest)
#`(define-serializable-struct/versions/derived #,stx . rest)])) #`(define-serializable-struct/versions/derived #,stx #t . rest)]))
(define-syntax (serializable-struct/versions stx)
(syntax-case stx ()
[(_ id super-id . rest)
(and (identifier? #'id)
(identifier? #'super-id))
#`(define-serializable-struct/versions/derived #,stx #f (id super-id) . rest)]
[(_ id vers (field ...) . rest)
(and (identifier? #'id)
(number? (syntax-e #'vers)))
#`(define-serializable-struct/versions/derived #,stx #f id vers (field ...) . rest)]))
(define-syntax (define-serializable-struct stx) (define-syntax (define-serializable-struct stx)
(syntax-case stx () (syntax-case stx ()
[(_ id/sup (field ...) prop ...) [(_ id/sup (field ...) prop ...)
#`(define-serializable-struct/versions/derived #,stx #`(define-serializable-struct/versions/derived #,stx #t
id/sup 0 (field ...) () prop ...)] id/sup 0 (field ...) () prop ...)]
[(_ . rest) [(_ . rest)
#`(define-struct/derived #,stx . rest)])) #`(define-struct/derived #,stx . rest)]))
(define-syntax (serializable-struct stx)
(syntax-case stx ()
[(_ id super-id (field ...) prop ...)
(and (identifier? #'id)
(identifier? #'super-id))
#`(define-serializable-struct/versions/derived #,stx #f
(id super-id) 0 (field ...) () prop ...)]
[(_ id (field ...) prop ...)
(and (identifier? #'id)
(identifier? #'super-id))
#`(define-serializable-struct/versions/derived #,stx #f
id 0 (field ...) () prop ...)]))
) )

View File

@ -6,7 +6,7 @@
(define (test/gui . tests) (define (test/gui . tests)
(apply (make-gui-runner) tests)) (apply (make-gui-runner) tests))
(define test/c (or/c rktunit-test-case? rktunit-test-suite?)) (define test/c (or/c racunit-test-case? racunit-test-suite?))
(provide/contract (provide/contract
[test/gui [test/gui

View File

@ -1,13 +1,13 @@
#lang setup/infotab #lang setup/infotab
(define name "RktUnit") (define name "RacUnit")
(define blurb '((p "RktUnit is a unit testing framework based on the " (define blurb '((p "RacUnit is a unit testing framework based on the "
" Extreme Programming unit test frameworks"))) " Extreme Programming unit test frameworks")))
(define scribblings '(("scribblings/rktunit.scrbl" (multi-page) (tool)))) (define scribblings '(("scribblings/racunit.scrbl" (multi-page) (tool))))
(define tools '[("tool.rkt")]) (define tools '[("tool.rkt")])
(define tool-names '["RktUnit DrRacket integration"]) (define tool-names '["RacUnit DrRacket integration"])
(define homepage "http://schematics.sourceforge.net/") (define homepage "http://schematics.sourceforge.net/")
(define url "http://schematics.sourceforge.net/") (define url "http://schematics.sourceforge.net/")

View File

@ -4,10 +4,10 @@
;; struct test : ;; struct test :
(define-struct test ()) (define-struct test ())
;; struct (rktunit-test-case test) : (U string #f) thunk ;; struct (racunit-test-case test) : (U string #f) thunk
(define-struct (rktunit-test-case test) (name action) #:transparent) (define-struct (racunit-test-case test) (name action) #:transparent)
;; struct (rktunit-test-suite test) : string (fdown fup fhere seed -> (listof test-result)) thunk thunk ;; struct (racunit-test-suite test) : string (fdown fup fhere seed -> (listof test-result)) thunk thunk
(define-struct (rktunit-test-suite test) (name tests before after) #:transparent) (define-struct (racunit-test-suite test) (name tests before after) #:transparent)
;; struct exn:test exn : () ;; struct exn:test exn : ()
;; ;;
@ -33,10 +33,10 @@
(define-struct (test-success test-result) (result)) (define-struct (test-success test-result) (result))
(provide/contract (provide/contract
(struct (rktunit-test-case test) (struct (racunit-test-case test)
((name (or/c string? false/c)) ((name (or/c string? false/c))
(action (-> any)))) (action (-> any))))
(struct (rktunit-test-suite test) (struct (racunit-test-suite test)
((name string?) ((name string?)
(tests procedure?) (tests procedure?)
(before (-> any)) (before (-> any))

View File

@ -11,7 +11,7 @@
;; Infrastructure ---------------------------------------------- ;; Infrastructure ----------------------------------------------
;; The continuation mark under which all check-info is keyed ;; The continuation mark under which all check-info is keyed
(define check-info-mark (gensym 'rktunit)) (define check-info-mark (gensym 'racunit))
;; (continuation-mark-set -> (listof check-info)) ;; (continuation-mark-set -> (listof check-info))
(define (check-info-stack marks) (define (check-info-stack marks)

View File

@ -5,20 +5,20 @@
;; Frame size preferences ;; Frame size preferences
(preferences:set-default 'rktunit:frame:width 400 exact-positive-integer?) (preferences:set-default 'racunit:frame:width 400 exact-positive-integer?)
(preferences:set-default 'rktunit:frame:height 400 exact-positive-integer?) (preferences:set-default 'racunit:frame:height 400 exact-positive-integer?)
(define pref:width (pref:get/set 'rktunit:frame:width)) (define pref:width (pref:get/set 'racunit:frame:width))
(define pref:height (pref:get/set 'rktunit:frame:height)) (define pref:height (pref:get/set 'racunit:frame:height))
;; CONSTANTS ;; CONSTANTS
;; Some of these are obsolete, given the preferences above. ;; Some of these are obsolete, given the preferences above.
(define DETAILS-CANVAS-INIT-WIDTH 400) (define DETAILS-CANVAS-INIT-WIDTH 400)
(define FRAME-LABEL "RktUnit") (define FRAME-LABEL "RacUnit")
(define FRAME-INIT-HEIGHT 400) (define FRAME-INIT-HEIGHT 400)
(define TREE-INIT-WIDTH 240) (define TREE-INIT-WIDTH 240)
(define TREE-COLORIZE-CASES #t) (define TREE-COLORIZE-CASES #t)
(define DIALOG-ERROR-TITLE "RktUnit: Error") (define DIALOG-ERROR-TITLE "RacUnit: Error")
(define STATUS-SUCCESS 'success) (define STATUS-SUCCESS 'success)
(define STATUS-FAILURE 'failure) (define STATUS-FAILURE 'failure)
(define STATUS-ERROR 'error) (define STATUS-ERROR 'error)

View File

@ -25,18 +25,18 @@
;; create-model : test suite<%>/#f -> result<%> ;; create-model : test suite<%>/#f -> result<%>
(define/public (create-model test parent) (define/public (create-model test parent)
(define result (define result
(cond [(rktunit-test-case? test) (cond [(racunit-test-case? test)
(new case-result% (new case-result%
(controller this) (controller this)
(test test) (test test)
(name (or (rktunit-test-case-name test) (name (or (racunit-test-case-name test)
"<unnamed test-case>")) "<unnamed test-case>"))
(parent parent))] (parent parent))]
[(rktunit-test-suite? test) [(racunit-test-suite? test)
(new suite-result% (new suite-result%
(controller this) (controller this)
(test test) (test test)
(name (or (rktunit-test-suite-name test) (name (or (racunit-test-suite-name test)
"<unnamed test-suite>")) "<unnamed test-suite>"))
(parent parent))])) (parent parent))]))
(send/i view view<%> create-view-link result parent) (send/i view view<%> create-view-link result parent)

View File

@ -48,8 +48,8 @@
#| #|
(define/public (run) (define/public (run)
(let ([custodian (make-custodian)] (let ([custodian (make-custodian)]
[before (rktunit-test-suite-before test)] [before (racunit-test-suite-before test)]
[after (rktunit-test-suite-after test)]) [after (racunit-test-suite-after test)])
(parameterize [(current-custodian custodian)] (parameterize [(current-custodian custodian)]
(dynamic-wind (dynamic-wind
before before
@ -112,8 +112,8 @@
(call-with-continuation-prompt (call-with-continuation-prompt
(lambda () (lambda ()
(time-apply run-test-case (time-apply run-test-case
(list (rktunit-test-case-name test) (list (racunit-test-case-name test)
(rktunit-test-case-action test)))))]) (racunit-test-case-action test)))))])
(values (car results) (list cputime realtime gctime)))) (values (car results) (list cputime realtime gctime))))
(define (make-output-ports) (define (make-output-ports)

View File

Before

Width:  |  Height:  |  Size: 513 B

After

Width:  |  Height:  |  Size: 513 B

View File

@ -7,7 +7,7 @@
(provide insert-text (provide insert-text
ext:text% ext:text%
rktunit-style-map) racunit-style-map)
;; insert-text : text% string style-delta% -> void ;; insert-text : text% string style-delta% -> void
(define (insert-text e text style) (define (insert-text e text style)
@ -20,7 +20,7 @@
(define ext:text-mixin (define ext:text-mixin
(mixin (text<%>) () (mixin (text<%>) ()
(init-field (style-map rktunit-style-map)) (init-field (style-map racunit-style-map))
(inherit last-position (inherit last-position
change-style change-style
set-clickback set-clickback
@ -139,7 +139,7 @@
[error . ,style:red] [error . ,style:red]
[value . ,style:darkblue])) [value . ,style:darkblue]))
(define rktunit-styles (define racunit-styles
`([test-unexecuted . ,style:gray] `([test-unexecuted . ,style:gray]
[test-success . ,style:green] [test-success . ,style:green]
[test-failure . ,style:red] [test-failure . ,style:red]
@ -181,7 +181,7 @@
(extend-style-map empty-style-map (extend-style-map empty-style-map
basic-styles)) basic-styles))
;; rktunit-style-map : style-map<%> ;; racunit-style-map : style-map<%>
(define rktunit-style-map (define racunit-style-map
(extend-style-map basic-style-map (extend-style-map basic-style-map
rktunit-styles)) racunit-styles))

View File

@ -13,7 +13,7 @@
(provide make-view-frame (provide make-view-frame
view%) view%)
(define style-map rktunit-style-map) (define style-map racunit-style-map)
#| #|
@ -50,7 +50,7 @@ still be there, just not visible?
controller) controller)
(super-new) (super-new)
(define editor (new ext:text% (style-map rktunit-style-map))) (define editor (new ext:text% (style-map racunit-style-map)))
(define renderer (define renderer
(new model-renderer% (new model-renderer%
(controller controller) (controller controller)
@ -146,7 +146,7 @@ still be there, just not visible?
;; If the view-link has not been created, ;; If the view-link has not been created,
;; yield until it is. ;; yield until it is.
(unless (yield) (unless (yield)
(error 'rktunit-gui (error 'racunit-gui
"internal error: no progress waiting for view-link")) "internal error: no progress waiting for view-link"))
(do-model-update model)]))) (do-model-update model)])))

View File

@ -51,12 +51,12 @@
;; data so FP is a bit ugly]. ;; data so FP is a bit ugly].
(define (foldts fdown fup fhere seed test) (define (foldts fdown fup fhere seed test)
(cond (cond
((rktunit-test-case? test) ((racunit-test-case? test)
(fhere test (fhere test
(rktunit-test-case-name test) (racunit-test-case-name test)
(rktunit-test-case-action test) (racunit-test-case-action test)
seed)) seed))
((rktunit-test-suite? test) ((racunit-test-suite? test)
(apply-test-suite test fdown fup fhere seed)) (apply-test-suite test fdown fup fhere seed))
(else (else
(raise (raise

View File

@ -27,14 +27,14 @@
(define (test-suite-test-case-around fhere) (define (test-suite-test-case-around fhere)
(lambda (thunk) (lambda (thunk)
(let* ([name (current-test-name)] (let* ([name (current-test-name)]
[test (make-rktunit-test-case name thunk)] [test (make-racunit-test-case name thunk)]
[seed (current-seed)]) [seed (current-seed)])
(current-seed (fhere test name thunk seed))))) (current-seed (fhere test name thunk seed)))))
(define (test-suite-check-around fhere) (define (test-suite-check-around fhere)
(lambda (thunk) (lambda (thunk)
(let* ([name #f] (let* ([name #f]
[test (make-rktunit-test-case name thunk)] [test (make-racunit-test-case name thunk)]
[seed (current-seed)]) [seed (current-seed)])
(current-seed (fhere test name thunk seed))))) (current-seed (fhere test name thunk seed)))))
@ -42,12 +42,12 @@
(define delayed-test-case-around (define delayed-test-case-around
(lambda (thunk) (lambda (thunk)
(let ([name (current-test-name)]) (let ([name (current-test-name)])
(make-rktunit-test-case name thunk)))) (make-racunit-test-case name thunk))))
(define delayed-check-around (define delayed-check-around
(lambda (thunk) (lambda (thunk)
(let ([name #f]) (let ([name #f])
(make-rktunit-test-case name thunk)))) (make-racunit-test-case name thunk))))
(define-syntax delay-test (define-syntax delay-test
(syntax-rules () (syntax-rules ()
@ -58,12 +58,12 @@
test test1 ...)])) test test1 ...)]))
(define (apply-test-suite suite fdown fup fhere seed) (define (apply-test-suite suite fdown fup fhere seed)
(let* ([name (rktunit-test-suite-name suite)] (let* ([name (racunit-test-suite-name suite)]
[tests (rktunit-test-suite-tests suite)] [tests (racunit-test-suite-tests suite)]
[before (rktunit-test-suite-before suite)] [before (racunit-test-suite-before suite)]
[after (rktunit-test-suite-after suite)] [after (racunit-test-suite-after suite)]
[kid-seed (fdown suite name before after seed)] [kid-seed (fdown suite name before after seed)]
[kid-seed ((rktunit-test-suite-tests suite) fdown fup fhere kid-seed)]) [kid-seed ((racunit-test-suite-tests suite) fdown fup fhere kid-seed)])
(fup suite name before after seed kid-seed))) (fup suite name before after seed kid-seed)))
;; test-suite : name [#:before thunk] [#:after thunk] test ... ;; test-suite : name [#:before thunk] [#:after thunk] test ...
@ -84,7 +84,7 @@
[the-tests [the-tests
(lambda (fdown fup fhere seed) (lambda (fdown fup fhere seed)
(define (run/inner x) (define (run/inner x)
(cond [(rktunit-test-suite? x) (cond [(racunit-test-suite? x)
(current-seed (current-seed
(apply-test-suite x fdown fup fhere (current-seed)))] (apply-test-suite x fdown fup fhere (current-seed)))]
[(list? x) [(list? x)
@ -103,7 +103,7 @@
[(not (string? the-name)) [(not (string? the-name))
(raise-type-error 'test-suite "test-suite name as string" the-name)] (raise-type-error 'test-suite "test-suite name as string" the-name)]
[else [else
(make-rktunit-test-suite (make-racunit-test-suite
the-name the-name
the-tests the-tests
before-thunk before-thunk
@ -138,13 +138,13 @@
(for-each (for-each
(lambda (t) (lambda (t)
(cond (cond
[(rktunit-test-suite? t) [(racunit-test-suite? t)
(current-seed (apply-test-suite t fdown fup fhere (current-seed)))] (current-seed (apply-test-suite t fdown fup fhere (current-seed)))]
[(rktunit-test-case? t) [(racunit-test-case? t)
(current-seed (current-seed
(fhere t (fhere t
(rktunit-test-case-name t) (racunit-test-case-name t)
(rktunit-test-case-action t) (racunit-test-case-action t)
(current-seed)))] (current-seed)))]
[else [else
(raise (raise
@ -158,7 +158,7 @@
;; ;;
;; Construct a test suite from a list of tests ;; Construct a test suite from a list of tests
(define (make-test-suite name #:before [before void-thunk] #:after [after void-thunk] tests) (define (make-test-suite name #:before [before void-thunk] #:after [after void-thunk] tests)
(make-rktunit-test-suite name (make-racunit-test-suite name
(tests->test-suite-action tests) (tests->test-suite-action tests)
before before
after)) after))

View File

@ -15,8 +15,8 @@
(struct-out test-failure) (struct-out test-failure)
(struct-out test-error) (struct-out test-error)
(struct-out test-success) (struct-out test-success)
(struct-out rktunit-test-case) (struct-out racunit-test-case)
(struct-out rktunit-test-suite) (struct-out racunit-test-suite)
with-check-info with-check-info
with-check-info* with-check-info*
@ -42,9 +42,9 @@
test-suite test-suite
make-test-suite make-test-suite
delay-test delay-test
(rename-out [make-rktunit-test-case make-test-case] (rename-out [make-racunit-test-case make-test-case]
[rktunit-test-case? test-case?] [racunit-test-case? test-case?]
[rktunit-test-suite? test-suite?]) [racunit-test-suite? test-suite?])
define-test-suite define-test-suite
define/provide-test-suite define/provide-test-suite

View File

@ -3,7 +3,7 @@
@title{Acknowlegements} @title{Acknowlegements}
The following people have contributed to RktUnit: The following people have contributed to RacUnit:
@itemize[ @itemize[
@item{Robby Findler pushed me to release version 3} @item{Robby Findler pushed me to release version 3}
@ -12,7 +12,7 @@ The following people have contributed to RktUnit:
suggested renaming @racket[test/text-ui]} suggested renaming @racket[test/text-ui]}
@item{Dave Gurnell reported a bug in check-not-exn and @item{Dave Gurnell reported a bug in check-not-exn and
suggested improvements to RktUnit} suggested improvements to RacUnit}
@item{Danny Yoo reported a bug in and provided a fix for @item{Danny Yoo reported a bug in and provided a fix for
trim-current-directory} trim-current-directory}
@ -30,7 +30,7 @@ The following people have contributed to RktUnit:
@item{Jose A. Ortega Ruiz alerted me a problem in the @item{Jose A. Ortega Ruiz alerted me a problem in the
packaging system and helped fix it.} packaging system and helped fix it.}
@item{Sebastian H. Seidel provided help packaging RktUnit @item{Sebastian H. Seidel provided help packaging RacUnit
into a .plt} into a .plt}
@item{Don Blaheta provided the method for grabbing line number @item{Don Blaheta provided the method for grabbing line number

View File

@ -1,10 +1,10 @@
#lang scribble/doc #lang scribble/doc
@(require "base.rkt") @(require "base.rkt")
@title[#:tag "api"]{RktUnit API} @title[#:tag "api"]{RacUnit API}
@defmodule[rktunit @defmodule[racunit
#:use-sources (rktunit)] #:use-sources (racunit)]
@include-section["overview.scrbl"] @include-section["overview.scrbl"]
@include-section["check.scrbl"] @include-section["check.scrbl"]

View File

@ -6,15 +6,15 @@
(for-label scheme/base (for-label scheme/base
scheme/contract scheme/contract
rktunit racunit
rktunit/text-ui racunit/text-ui
rktunit/gui)) racunit/gui))
(provide (provide
(all-from-out scribble/eval (all-from-out scribble/eval
scribble/manual) scribble/manual)
(for-label (all-from-out scheme/base (for-label (all-from-out scheme/base
scheme/contract scheme/contract
rktunit racunit
rktunit/text-ui racunit/text-ui
rktunit/gui))) racunit/gui)))

View File

@ -3,7 +3,7 @@
@title{Checks} @title{Checks}
Checks are the basic building block of RktUnit. A check Checks are the basic building block of RacUnit. A check
checks some condition. If the condition holds the check checks some condition. If the condition holds the check
evaluates to @racket[#t]. If the condition doesn't hold the evaluates to @racket[#t]. If the condition doesn't hold the
check raises an instance of @racket[exn:test:check] with check raises an instance of @racket[exn:test:check] with
@ -16,7 +16,7 @@ their arguments. You can use check as first class
functions, though you will lose precision in the reported functions, though you will lose precision in the reported
source locations if you do so. source locations if you do so.
The following are the basic checks RktUnit provides. You The following are the basic checks RacUnit provides. You
can create your own checks using @racket[define-check]. can create your own checks using @racket[define-check].
@defproc[(check (op (-> any any any)) @defproc[(check (op (-> any any any))

View File

@ -147,7 +147,7 @@ creates test cases within the suite, with the given names and
body expressions. body expressions.
As far I know no-one uses this macro, so it might disappear As far I know no-one uses this macro, so it might disappear
in future versions of RktUnit.} in future versions of RacUnit.}
} }

View File

@ -48,5 +48,5 @@ file. The after action deletes it.
This somewhat curious macro evaluates the given tests in a This somewhat curious macro evaluates the given tests in a
context where @racket[current-test-case-around] is context where @racket[current-test-case-around] is
parameterized to @racket[test-suite-test-case-around]. This parameterized to @racket[test-suite-test-case-around]. This
has been useful in testing RktUnit. It might be useful has been useful in testing RacUnit. It might be useful
for you if you create test cases that create test cases.} for you if you create test cases that create test cases.}

View File

@ -1,6 +1,6 @@
#lang scheme/base #lang scheme/base
(require rktunit (require racunit
"file.rkt") "file.rkt")
(check-equal? (my-+ 1 1) 2) (check-equal? (my-+ 1 1) 2)

View File

@ -14,8 +14,8 @@ Note that @racket[require/expose] can be a bit fragile,
especially when mixed with compiled code. Use at your own risk! especially when mixed with compiled code. Use at your own risk!
} }
This example gets @racket[make-failure-test], which is defined in a RktUnit test: This example gets @racket[make-failure-test], which is defined in a RacUnit test:
@racketblock[ @racketblock[
(require/expose rktunit/private/check-test (make-failure-test)) (require/expose racunit/private/check-test (make-failure-test))
] ]

View File

@ -1,9 +1,9 @@
#lang scribble/doc #lang scribble/doc
@(require "base.rkt") @(require "base.rkt")
@title{Overview of RktUnit} @title{Overview of RacUnit}
There are three basic data types in RktUnit: There are three basic data types in RacUnit:
@itemize[ @itemize[

View File

@ -1,10 +1,10 @@
#lang scribble/doc #lang scribble/doc
@(require "base.rkt") @(require "base.rkt")
@title[#:tag "philosophy"]{The Philosophy of RktUnit} @title[#:tag "philosophy"]{The Philosophy of RacUnit}
RktUnit is designed to allow tests to evolve in step with RacUnit is designed to allow tests to evolve in step with
the evolution of the program under testing. RktUnit the evolution of the program under testing. RacUnit
scales from the unstructed checks suitable for simple scales from the unstructed checks suitable for simple
programs to the complex structure necessary for large programs to the complex structure necessary for large
projects. projects.
@ -25,9 +25,9 @@ checking are of the form:
(equal? (length '(a b)) 2) (equal? (length '(a b)) 2)
] ]
RktUnit directly supports this style of testing. A check RacUnit directly supports this style of testing. A check
on its own is a valid test. So the above examples may be on its own is a valid test. So the above examples may be
written in RktUnit as: written in RacUnit as:
@racketblock[ @racketblock[
(check-equal? (length null) 0) (check-equal? (length null) 0)
@ -35,7 +35,7 @@ written in RktUnit as:
(check-equal? (length '(a b)) 2) (check-equal? (length '(a b)) 2)
] ]
Simple programs now get all the benefits of RktUnit with Simple programs now get all the benefits of RacUnit with
very little overhead. very little overhead.
There are limitations to this style of testing that more There are limitations to this style of testing that more
@ -45,7 +45,7 @@ it does not make sense to evaluate some expressions if
earlier ones have failed. This type of program needs a way earlier ones have failed. This type of program needs a way
to group expressions so that a failure in one group causes to group expressions so that a failure in one group causes
evaluation of that group to stop and immediately proceed to evaluation of that group to stop and immediately proceed to
the next group. In RktUnit all that is required is to the next group. In RacUnit all that is required is to
wrap a @racket[test-begin] expression around a group of wrap a @racket[test-begin] expression around a group of
expressions: expressions:
@ -62,7 +62,7 @@ be evaluated.
Notice that all the previous tests written in the simple Notice that all the previous tests written in the simple
style are still valid. Introducing grouping is a local style are still valid. Introducing grouping is a local
change only. This is a key feature of RktUnit's support change only. This is a key feature of RacUnit's support
for the evolution of the program. for the evolution of the program.
The programmer may wish to name a group of tests. This is The programmer may wish to name a group of tests. This is
@ -79,7 +79,7 @@ Most programs will stick with this style. However,
programmers writing very complex programs may wish to programmers writing very complex programs may wish to
maintain separate groups of tests for different parts of the maintain separate groups of tests for different parts of the
program, or run their tests in different ways to the normal program, or run their tests in different ways to the normal
RktUnit manner (for example, test results may be logged RacUnit manner (for example, test results may be logged
for the purpose of improving software quality, or they may for the purpose of improving software quality, or they may
be displayed on a website to indicate service quality). For be displayed on a website to indicate service quality). For
these programmers it is necessary to delay the execution of these programmers it is necessary to delay the execution of
@ -104,15 +104,15 @@ outside the suite continue to evaluate as before.
@section{Historical Context} @section{Historical Context}
Most testing frameworks, including earlier versions of Most testing frameworks, including earlier versions of
RktUnit, support only the final form of testing. This is RacUnit, support only the final form of testing. This is
likely due to the influence of the SUnit testing framework, likely due to the influence of the SUnit testing framework,
which is the ancestor of RktUnit and the most widely used which is the ancestor of RacUnit and the most widely used
frameworks in Java, .Net, Python, and Ruby, and many other frameworks in Java, .Net, Python, and Ruby, and many other
languages. That this is insufficient for all users is languages. That this is insufficient for all users is
apparent if one considers the proliferation of ``simpler'' apparent if one considers the proliferation of ``simpler''
testing frameworks in Racket such as SRFI-78, or the testing frameworks in Racket such as SRFI-78, or the
practice of beginner programmers. Unfortunately these practice of beginner programmers. Unfortunately these
simpler methods are inadequate for testing larger simpler methods are inadequate for testing larger
systems. To the best of my knowledge RktUnit is the only systems. To the best of my knowledge RacUnit is the only
testing framework that makes a conscious effort to support testing framework that makes a conscious effort to support
the testing style of all levels of programmer. the testing style of all levels of programmer.

View File

@ -1,7 +1,7 @@
#lang scribble/doc #lang scribble/doc
@(require "base.rkt") @(require "base.rkt")
@title[#:tag "quick-start"]{Quick Start Guide for RktUnit} @title[#:tag "quick-start"]{Quick Start Guide for RacUnit}
Suppose we have code contained in @tt{file.rkt}, which Suppose we have code contained in @tt{file.rkt}, which
implements buggy versions of @racket[+] and @racket[-] implements buggy versions of @racket[+] and @racket[-]
@ -24,15 +24,15 @@ racket/base
my-*) my-*)
] ]
We want to test this code with RktUnit. We start by We want to test this code with RacUnit. We start by
creating a file called @tt{file-test.rkt} to contain our creating a file called @tt{file-test.rkt} to contain our
tests. At the top of @tt{file-test.rkt} we import tests. At the top of @tt{file-test.rkt} we import
RktUnit and @tt{file.rkt}: RacUnit and @tt{file.rkt}:
@racketmod[ @racketmod[
racket/base racket/base
(require rktunit (require racunit
"file.rkt") "file.rkt")
] ]
@ -43,7 +43,7 @@ Now we add some tests to check our library:
(check-equal? (my-* 1 2) 2 "Simple multiplication") (check-equal? (my-* 1 2) 2 "Simple multiplication")
] ]
This is all it takes to define tests in RktUnit. Now This is all it takes to define tests in RacUnit. Now
evaluate this file and see if the library is correct. evaluate this file and see if the library is correct.
Here's the result I get: Here's the result I get:
@ -63,13 +63,13 @@ expected: 2
The first @racket[#t] indicates the first test passed. The The first @racket[#t] indicates the first test passed. The
second test failed, as shown by the message. second test failed, as shown by the message.
Requiring RktUnit and writing checks is all you need to Requiring RacUnit and writing checks is all you need to
get started testing, but let's take a little bit more time get started testing, but let's take a little bit more time
to look at some features beyond the essentials. to look at some features beyond the essentials.
Let's say we want to check that a number of properties hold. Let's say we want to check that a number of properties hold.
How do we do this? So far we've only seen checks of a How do we do this? So far we've only seen checks of a
single expression. In RktUnit a check is always a single single expression. In RacUnit a check is always a single
expression, but we can group checks into units called test expression, but we can group checks into units called test
cases. Here's a simple test case written using the cases. Here's a simple test case written using the
@racket[test-begin] form: @racket[test-begin] form:
@ -91,7 +91,7 @@ Evalute this and you should see an error message like:
A test A test
... has a FAILURE ... has a FAILURE
name: check-pred name: check-pred
location: (#<path:/Users/noel/programming/schematics/rktunit/branches/v3/doc/file-test.rkt> 14 6 252 22) location: (#<path:/Users/noel/programming/schematics/racunit/branches/v3/doc/file-test.rkt> 14 6 252 22)
expression: (check-pred even? elt) expression: (check-pred even? elt)
params: (#<procedure:even?> 9) params: (#<procedure:even?> 9)
-------------------- --------------------
@ -147,13 +147,13 @@ tests, allowing you to choose how you run your tests. You
might, for example, print the results to the screen or log might, for example, print the results to the screen or log
them to a file. them to a file.
Let's run our tests, using RktUnit's simple textual user Let's run our tests, using RacUnit's simple textual user
interface (there are fancier interfaces available but this interface (there are fancier interfaces available but this
will do for our example). In @tt{file-test.rkt} add the will do for our example). In @tt{file-test.rkt} add the
following lines: following lines:
@racketblock[ @racketblock[
(require rktunit/text-ui) (require racunit/text-ui)
(run-tests file-tests) (run-tests file-tests)
] ]
@ -161,6 +161,6 @@ following lines:
Now evaluate the file and you should see similar output Now evaluate the file and you should see similar output
again. again.
These are the basics of RktUnit. Refer to the These are the basics of RacUnit. Refer to the
documentation below for more advanced topics, such as documentation below for more advanced topics, such as
defining your own checks. Have fun! defining your own checks. Have fun!

View File

@ -1,12 +1,12 @@
#lang scribble/doc #lang scribble/doc
@(require "base.rkt") @(require "base.rkt")
@title{@bold{RktUnit}: Unit Testing for Racket} @title{@bold{RacUnit}: Unit Testing for Racket}
@author[(author+email "Noel Welsh" "noelwelsh@gmail.com") @author[(author+email "Noel Welsh" "noelwelsh@gmail.com")
(author+email "Ryan Culpepper" "ryan_sml@yahoo.com")] (author+email "Ryan Culpepper" "ryan_sml@yahoo.com")]
RktUnit is a unit-testing framework for Racket. It RacUnit is a unit-testing framework for Racket. It
is designed to handle the needs of all Racket programmers, is designed to handle the needs of all Racket programmers,
from novices to experts. from novices to experts.

View File

@ -12,7 +12,7 @@ There are also miscellaneous Scribble fixes.
@section{Version 3} @section{Version 3}
This version of RktUnit is largely backwards compatible This version of RacUnit is largely backwards compatible
with version 2 but there are significant changes to the with version 2 but there are significant changes to the
underlying model, justifying incrementing the major version underlying model, justifying incrementing the major version
number. These changes are best explained in number. These changes are best explained in

View File

@ -3,14 +3,14 @@
@title[#:tag "running"]{Programmatically Running Tests and Inspecting Results} @title[#:tag "running"]{Programmatically Running Tests and Inspecting Results}
RktUnit provides an API for running tests, from which RacUnit provides an API for running tests, from which
custom UIs can be created. custom UIs can be created.
@section{Result Types} @section{Result Types}
@defstruct[(exn:test exn) ()]{ @defstruct[(exn:test exn) ()]{
The base structure for RktUnit exceptions. You should The base structure for RacUnit exceptions. You should
never catch instances of this type, only the subtypes never catch instances of this type, only the subtypes
documented below.} documented below.}
@ -187,7 +187,7 @@ recorded, and so on. To do so the functions that run the
test cases need to know what type the test case has, and test cases need to know what type the test case has, and
hence is is necessary to provide this information. hence is is necessary to provide this information.
If you've made it this far you truly are a master RktUnit If you've made it this far you truly are a master RacUnit
hacker. As a bonus prize we'll just mention that the code hacker. As a bonus prize we'll just mention that the code
in hash-monad.rkt and monad.rkt might be of interest for in hash-monad.rkt and monad.rkt might be of interest for
constructing user interfaces. The API is still in flux, so constructing user interfaces. The API is still in flux, so

View File

@ -3,13 +3,13 @@
@title[#:tag "ui"]{User Interfaces} @title[#:tag "ui"]{User Interfaces}
RktUnit provides a textual and a graphical user interface RacUnit provides a textual and a graphical user interface
@section{Textual User Interface} @section{Textual User Interface}
@defmodule[rktunit/text-ui] @defmodule[racunit/text-ui]
The textual UI is in the @racketmodname[rktunit/text-ui] module. The textual UI is in the @racketmodname[racunit/text-ui] module.
It is run via the @racket[run-tests] function. It is run via the @racket[run-tests] function.
@defproc[(run-tests (test (or/c test-case? test-suite?)) @defproc[(run-tests (test (or/c test-case? test-suite?))
@ -33,15 +33,15 @@ information.
@section{Graphical User Interface} @section{Graphical User Interface}
@defmodule[rktunit/gui] @defmodule[racunit/gui]
RktUnit also provides a GUI test runner, available from the RacUnit also provides a GUI test runner, available from the
@racketmodname[rktunit/gui] module. @racketmodname[racunit/gui] module.
@defproc[(test/gui [test (or/c test-case? test-suite?)] ...) @defproc[(test/gui [test (or/c test-case? test-suite?)] ...)
any]{ any]{
Creates a new RktUnit GUI window and runs each @racket[test]. The Creates a new RacUnit GUI window and runs each @racket[test]. The
GUI is updated as tests complete. GUI is updated as tests complete.
} }
@ -49,7 +49,7 @@ GUI is updated as tests complete.
@defproc[(make-gui-runner) @defproc[(make-gui-runner)
(-> (or/c test-case? test-suite?) ... any)]{ (-> (or/c test-case? test-suite?) ... any)]{
Creates a new RktUnit GUI window and returns a procedure that, when Creates a new RacUnit GUI window and returns a procedure that, when
applied, runs the given tests and displays the results in the GUI. applied, runs the given tests and displays the results in the GUI.
} }

View File

@ -11,7 +11,7 @@
;; CONSTANTS ;; CONSTANTS
(define BACKTRACE-NO-MESSAGE "No message.") (define BACKTRACE-NO-MESSAGE "No message.")
(define LINK-MODULE-SPEC 'rktunit/private/gui/drracket-link) (define LINK-MODULE-SPEC 'racunit/private/gui/drracket-link)
(define-namespace-anchor drracket-ns-anchor) (define-namespace-anchor drracket-ns-anchor)

View File

@ -1,3 +1,3 @@
#lang racket #lang racket
(require rktunit/gui) (require racunit/gui)
(provide (all-from-out rktunit/gui)) (provide (all-from-out racunit/gui))

View File

@ -1,3 +1,3 @@
#lang racket #lang racket
(require rktunit) (require racunit)
(provide (all-from-out rktunit)) (provide (all-from-out racunit))

View File

@ -1,3 +1,3 @@
#lang racket #lang racket
(require rktunit/text-ui) (require racunit/text-ui)
(provide (all-from-out rktunit/text-ui)) (provide (all-from-out racunit/text-ui))

View File

@ -7,7 +7,7 @@
racket/file racket/file
racket/sandbox racket/sandbox
racket/promise racket/promise
mzlib/string racket/string
(for-syntax racket/base)) (for-syntax racket/base))
(provide interaction (provide interaction
@ -97,18 +97,24 @@
(map (map
(lambda (s) (lambda (s)
(car (format-output s error-color))) (car (format-output s error-color)))
(let sloop ([s (caar val-list+outputs)]) (filter
(if ((string-length s) . > . maxlen) (lambda (s) (not (equal? s "")))
;; break the error message into multiple lines: (let sloop ([s (caar val-list+outputs)])
(let loop ([pos (sub1 maxlen)]) (apply
(cond append
[(zero? pos) (cons (substring s 0 maxlen) (map (lambda (s)
(sloop (substring s maxlen)))] (if ((string-length s) . > . maxlen)
[(char-whitespace? (string-ref s pos)) ;; break the error message into multiple lines:
(cons (substring s 0 pos) (let loop ([pos (sub1 maxlen)])
(sloop (substring s (add1 pos))))] (cond
[else (loop (sub1 pos))])) [(zero? pos) (cons (substring s 0 maxlen)
(list s)))) (sloop (substring s maxlen)))]
[(char-whitespace? (string-ref s pos))
(cons (substring s 0 pos)
(sloop (substring s (add1 pos))))]
[else (loop (sub1 pos))]))
(list s)))
(regexp-split #rx"\n" s))))))
;; Normal result case: ;; Normal result case:
(let ([val-list (caar val-list+outputs)]) (let ([val-list (caar val-list+outputs)])
(if (equal? val-list (list (void))) (if (equal? val-list (list (void)))

File diff suppressed because it is too large Load Diff

View File

@ -4,57 +4,43 @@
@title[#:tag "compile"]{Compilation and Configuration} @title[#:tag "compile"]{Compilation and Configuration}
So far, we have talked about three main PLT Scheme executables: So far in this guide, we have mainly discussed DrRacket and
@exec{racket} (and @exec{gracket}). The main additional executable is
@exec{raco}, which is short for ``@bold{Ra}cket @bold{co}mmand.'' The
@exec{raco} program provides a command-line interface to many
additional tools for compiling Racket programs and maintaining a
Racket installation.
@itemize[ @itemize[
@item{DrScheme, which is the development environment.} @item{@exec{raco make} compiles Racket source to bytecode.
@item{@exec{mzscheme}, which is the console-based virtual machine for For example, if you have a program @filepath{take-over-world.rkt} and
running PLT Scheme programs (and that can be used as a
development environment in interactive mode);}
@item{@exec{mred}, which is like @exec{mzscheme}, but for GUI
applications.}
]
Three more executables help in compiling PLT Scheme programs and in
maintaining a PLT Scheme installation:
@itemize[
@item{@exec{mzc} is a command-line tool for miscellaneous tasks, such
as compiling Scheme source to bytecode, generating executables, and
building distribution packages, and compiling C-implemented
extensions to work with the run-time system. The @exec{mzc} is
described in @other-manual['(lib
"scribblings/mzc/mzc.scrbl")].
For example, if you have a program @filepath{take-over-world.ss} and
you'd like to compile it to bytecode, along with all of its you'd like to compile it to bytecode, along with all of its
dependencies, so that it loads more quickly, then run dependencies, so that it loads more quickly, then run
@commandline{mzc take-over-the-world.ss}} @commandline{raco make take-over-the-world.rkt}}
@item{@exec{setup-plt} is a command-line tool for managing a PLT
Scheme installation, including manually installed packages. The @item{@exec{raco setup} manages a Racket installation, including
@exec{setup-plt} tool is described in @other-manual['(lib manually installed packages.
"scribblings/setup-plt/setup-plt.scrbl")].
For example, if you create your own library @techlink{collection} For example, if you create your own library @techlink{collection}
called @filepath{take-over}, and you'd like to build all bytecode and called @filepath{take-over}, and you'd like to build all bytecode and
documentation for the collection, then run documentation for the collection, then run
@commandline{setup-plt -l take-over}} @commandline{raco setup -l take-over}}
@item{@exec{planet} is a command-line tool for managing packages that
are normally downloaded automatically, on demand. The @exec{planet} @item{@exec{raco planet} manages packages that are normally
tool is described in @other-manual['(lib "planet/planet.scrbl")]. downloaded automatically, on demand.
For example, if you'd like to see a list of @|PLaneT| packages that For example, if you'd like to see a list of @|PLaneT| packages that
are currently installed, then run are currently installed, then run
@commandline{planet show}} @commandline{raco planet show}}
] ]
For more information on @exec{raco}, see @other-manual['(lib
"scribblings/mzc/mzc.scrbl")].

View File

@ -1,5 +1,5 @@
#lang scheme #lang scheme
(require rktunit rktunit/text-ui "1.ss" "1b.ss") (require racunit racunit/text-ui "1.ss" "1b.ss")
(add (make-basic-customer 'mf "matthias" "brookstone")) (add (make-basic-customer 'mf "matthias" "brookstone"))
(add (make-basic-customer 'rf "robby" "beverly hills park")) (add (make-basic-customer 'rf "robby" "beverly hills park"))

View File

@ -1,5 +1,5 @@
#lang scheme #lang scheme
(require rktunit rktunit/text-ui "2.ss") (require racunit racunit/text-ui "2.ss")
(define s0 (initialize (flat-contract integer?) =)) (define s0 (initialize (flat-contract integer?) =))
(define s2 (push (push s0 2) 1)) (define s2 (push (push s0 2) 1))

View File

@ -1,5 +1,5 @@
#lang scheme #lang scheme
(require rktunit rktunit/text-ui "3.ss") (require racunit racunit/text-ui "3.ss")
(define d0 (initialize (flat-contract integer?) =)) (define d0 (initialize (flat-contract integer?) =))
(define d (put (put (put d0 'a 2) 'b 2) 'c 1)) (define d (put (put (put d0 'a 2) 'b 2) 'c 1))

View File

@ -1,5 +1,5 @@
#lang scheme #lang scheme
(require rktunit rktunit/text-ui "5.ss") (require racunit racunit/text-ui "5.ss")
(define s (put (put (initialize (flat-contract integer?) =) 2) 1)) (define s (put (put (initialize (flat-contract integer?) =) 2) 1))

View File

@ -7,7 +7,7 @@
@title[#:tag "control" #:style 'toc]{Exceptions and Control} @title[#:tag "control" #:style 'toc]{Exceptions and Control}
Scheme provides an especially rich set of control operations---not Racket provides an especially rich set of control operations---not
only operations for raising and catching exceptions, but also only operations for raising and catching exceptions, but also
operations for grabbing and restoring portions of a computation. operations for grabbing and restoring portions of a computation.
@ -27,22 +27,22 @@ computation.
(car 17) (car 17)
] ]
To catch an exception, use the @scheme[with-handlers] form: To catch an exception, use the @racket[with-handlers] form:
@specform[ @specform[
(with-handlers ([predicate-expr handler-expr] ...) (with-handlers ([predicate-expr handler-expr] ...)
body ...+) body ...+)
]{} ]{}
Each @scheme[_predicate-expr] in a handler determines a kind of Each @racket[_predicate-expr] in a handler determines a kind of
exception that is caught by the @scheme[with-handlers] form, and the exception that is caught by the @racket[with-handlers] form, and the
value representing the exception is passed to the handler procedure value representing the exception is passed to the handler procedure
produced by @scheme[_handler-expr]. The result of the produced by @racket[_handler-expr]. The result of the
@scheme[_handler-expr] is the result of the @scheme[with-handlers] @racket[_handler-expr] is the result of the @racket[with-handlers]
expression. expression.
For example, a divide-by-zero error raises an instance of the For example, a divide-by-zero error raises an instance of the
@scheme[exn:fail:contract:divide-by-zero] structure type: @racket[exn:fail:contract:divide-by-zero] structure type:
@interaction[ @interaction[
(with-handlers ([exn:fail:contract:divide-by-zero? (with-handlers ([exn:fail:contract:divide-by-zero?
@ -53,9 +53,9 @@ For example, a divide-by-zero error raises an instance of the
(car 17)) (car 17))
] ]
The @scheme[error] function is one way to raise your own exception. It The @racket[error] function is one way to raise your own exception. It
packages an error message and other information into an packages an error message and other information into an
@scheme[exn:fail] structure: @racket[exn:fail] structure:
@interaction[ @interaction[
(error "crash!") (error "crash!")
@ -63,11 +63,11 @@ packages an error message and other information into an
(error "crash!")) (error "crash!"))
] ]
The @scheme[exn:fail:contract:divide-by-zero] and @scheme[exn:fail] The @racket[exn:fail:contract:divide-by-zero] and @racket[exn:fail]
structure types are sub-types of the @scheme[exn] structure structure types are sub-types of the @racket[exn] structure
type. Exceptions raised by core forms and functions always raise an type. Exceptions raised by core forms and functions always raise an
instance of @scheme[exn] or one of its sub-types, but an exception instance of @racket[exn] or one of its sub-types, but an exception
does not have to be represented by a structure. The @scheme[raise] does not have to be represented by a structure. The @racket[raise]
function lets you raise any value as an exception: function lets you raise any value as an exception:
@interaction[ @interaction[
@ -78,7 +78,7 @@ function lets you raise any value as an exception:
(/ 1 0)) (/ 1 0))
] ]
Multiple @scheme[_predicate-expr]s in a @scheme[with-handlers] form Multiple @racket[_predicate-expr]s in a @racket[with-handlers] form
let you handle different kinds of exceptions in different ways. The let you handle different kinds of exceptions in different ways. The
predicates are tried in order, and if none of them match, then the predicates are tried in order, and if none of them match, then the
exception is propagated to enclosing contexts. exception is propagated to enclosing contexts.
@ -95,7 +95,7 @@ exception is propagated to enclosing contexts.
(always-fail -3)) (always-fail -3))
] ]
Using @scheme[(lambda (v) #t)] as a predicate captures all exceptions, of course: Using @racket[(lambda (v) #t)] as a predicate captures all exceptions, of course:
@interaction[ @interaction[
(with-handlers ([(lambda (v) #t) (lambda (v) 'oops)]) (with-handlers ([(lambda (v) #t) (lambda (v) 'oops)])
@ -104,9 +104,9 @@ Using @scheme[(lambda (v) #t)] as a predicate captures all exceptions, of course
Capturing all exceptions is usually a bad idea, however. If the user Capturing all exceptions is usually a bad idea, however. If the user
types Ctl-C in a terminal window or clicks the @onscreen{Stop} button types Ctl-C in a terminal window or clicks the @onscreen{Stop} button
in DrScheme to interrupt a computation, then normally the in DrRacket to interrupt a computation, then normally the
@scheme[exn:break] exception should not be caught. To catch only @racket[exn:break] exception should not be caught. To catch only
exceptions that represent errors, use @scheme[exn:fail?] as the exceptions that represent errors, use @racket[exn:fail?] as the
predicate: predicate:
@interaction[ @interaction[
@ -134,7 +134,7 @@ the way out if the expression is never caught:
But if control escapes ``all the way out,'' why does the @tech{REPL} But if control escapes ``all the way out,'' why does the @tech{REPL}
keep going after an error is printed? You might think that it's keep going after an error is printed? You might think that it's
because the @tech{REPL} wraps every interaction in a because the @tech{REPL} wraps every interaction in a
@scheme[with-handlers] form that catches all exceptions, but that's @racket[with-handlers] form that catches all exceptions, but that's
not quite the reason. not quite the reason.
The actual reason is that the @tech{REPL} wraps the interaction with a The actual reason is that the @tech{REPL} wraps the interaction with a
@ -145,11 +145,11 @@ nearest enclosing prompt. More precisely, each prompt has a
@deftech{prompt tag}, and there is a designated @deftech{default @deftech{prompt tag}, and there is a designated @deftech{default
prompt tag} that the uncaught-exception handler uses to @tech{abort}. prompt tag} that the uncaught-exception handler uses to @tech{abort}.
The @scheme[call-with-continuation-prompt] function installs a prompt The @racket[call-with-continuation-prompt] function installs a prompt
with a given @tech{prompt tag}, and then it evaluates a given thunk with a given @tech{prompt tag}, and then it evaluates a given thunk
under the prompt. The @scheme[default-continuation-prompt-tag] under the prompt. The @racket[default-continuation-prompt-tag]
function returns the @tech{default prompt tag}. The function returns the @tech{default prompt tag}. The
@scheme[abort-current-continuation] function escapes to the nearest @racket[abort-current-continuation] function escapes to the nearest
enclosing prompt that has a given @tech{prompt tag}. enclosing prompt that has a given @tech{prompt tag}.
@interaction[ @interaction[
@ -165,13 +165,13 @@ enclosing prompt that has a given @tech{prompt tag}.
(default-continuation-prompt-tag))) (default-continuation-prompt-tag)))
] ]
In @scheme[escape] above, the value @scheme[v] is wrapped in a In @racket[escape] above, the value @racket[v] is wrapped in a
procedure that is called after escaping to the enclosing prompt. procedure that is called after escaping to the enclosing prompt.
@tech{Prompts} and @tech{aborts} look very much like exception @tech{Prompts} and @tech{aborts} look very much like exception
handling and raising. Indeed, prompts and aborts are essentially a handling and raising. Indeed, prompts and aborts are essentially a
more primitive form of exceptions, and @scheme[with-handlers] and more primitive form of exceptions, and @racket[with-handlers] and
@scheme[raise] are implemented in terms of prompts and aborts. The @racket[raise] are implemented in terms of prompts and aborts. The
power of the more primitive forms is related to the word power of the more primitive forms is related to the word
``continuation'' in the operator names, as we discuss in the next ``continuation'' in the operator names, as we discuss in the next
section. section.
@ -182,7 +182,7 @@ section.
A @deftech{continuation} is a value that encapsulates a piece of an A @deftech{continuation} is a value that encapsulates a piece of an
expression context. The @scheme[call-with-composable-continuation] expression context. The @racket[call-with-composable-continuation]
function captures the @deftech{current continuation} starting outside function captures the @deftech{current continuation} starting outside
the current function call and running up to the nearest enclosing the current function call and running up to the nearest enclosing
prompt. (Keep in mind that each @tech{REPL} interaction is implicitly prompt. (Keep in mind that each @tech{REPL} interaction is implicitly
@ -190,31 +190,31 @@ wrapped in a prompt.)
For example, in For example, in
@schemeblock[ @racketblock[
(+ 1 (+ 1 (+ 1 0))) (+ 1 (+ 1 (+ 1 0)))
] ]
at the point where @scheme[0] is evaluated, the expression context at the point where @racket[0] is evaluated, the expression context
includes three nested addition expressions. We can grab that context by includes three nested addition expressions. We can grab that context by
changing @scheme[0] to grab the continuation before returning 0: changing @racket[0] to grab the continuation before returning 0:
@interaction[ @interaction[
#:eval cc-eval #:eval cc-eval
(define saved-k #f) (define saved-k #f)
(define (save-it!) (define (save-it!)
(call-with-composable-continuation (call-with-composable-continuation
(lambda (k) (code:comment @#,t{@scheme[k] is the captured continuation}) (lambda (k) (code:comment @#,t{@racket[k] is the captured continuation})
(set! saved-k k) (set! saved-k k)
0))) 0)))
(+ 1 (+ 1 (+ 1 (save-it!)))) (+ 1 (+ 1 (+ 1 (save-it!))))
] ]
The @tech{continuation} saved in @scheme[save-k] encapsulates the The @tech{continuation} saved in @racket[save-k] encapsulates the
program context @scheme[(+ 1 (+ 1 (+ 1 _?)))], where @scheme[_?] program context @racket[(+ 1 (+ 1 (+ 1 _?)))], where @racket[_?]
represents a place to plug in a result value---because that was the represents a place to plug in a result value---because that was the
expression context when @scheme[save-it!] was called. The expression context when @racket[save-it!] was called. The
@tech{continuation} is encapsulated so that it behaves like the @tech{continuation} is encapsulated so that it behaves like the
function @scheme[(lambda (v) (+ 1 (+ 1 (+ 1 v))))]: function @racket[(lambda (v) (+ 1 (+ 1 (+ 1 v))))]:
@interaction[ @interaction[
#:eval cc-eval #:eval cc-eval
@ -224,7 +224,7 @@ function @scheme[(lambda (v) (+ 1 (+ 1 (+ 1 v))))]:
] ]
The continuation captured by The continuation captured by
@scheme[call-with-composable-continuation] is determined dynamically, @racket[call-with-composable-continuation] is determined dynamically,
not syntactically. For example, with not syntactically. For example, with
@interaction[ @interaction[
@ -236,7 +236,7 @@ not syntactically. For example, with
(sum 5) (sum 5)
] ]
the continuation in @scheme[saved-k] becomes @scheme[(lambda (x) (+ 5 the continuation in @racket[saved-k] becomes @racket[(lambda (x) (+ 5
(+ 4 (+ 3 (+ 2 (+ 1 x))))))]: (+ 4 (+ 3 (+ 2 (+ 1 x))))))]:
@interaction[ @interaction[
@ -245,25 +245,25 @@ the continuation in @scheme[saved-k] becomes @scheme[(lambda (x) (+ 5
(saved-k 10) (saved-k 10)
] ]
A more traditional continuation operator in Scheme is A more traditional continuation operator in Racket is
@scheme[call-with-current-continuation], which is often abbreviated @racket[call-with-current-continuation], which is often abbreviated
@scheme[call/cc]. It is like @racket[call/cc]. It is like
@scheme[call-with-composable-continuation], but applying the captured @racket[call-with-composable-continuation], but applying the captured
continuation first @tech{aborts} (to the current @tech{prompt}) before continuation first @tech{aborts} (to the current @tech{prompt}) before
restoring the saved continuation. In addition, Scheme systems restoring the saved continuation. In addition, Racket systems
traditionally support a single prompt at the program start, instead of traditionally support a single prompt at the program start, instead of
allowing new prompts via allowing new prompts via
@scheme[call-with-continuation-prompt]. Continuations as in PLT Scheme @racket[call-with-continuation-prompt]. Continuations as in Racket
are sometimes called @deftech{delimited continuations}, since a are sometimes called @deftech{delimited continuations}, since a
program can introduce new delimiting prompts, and continuations as program can introduce new delimiting prompts, and continuations as
captured by @scheme[call-with-composable-continuation] are sometimes captured by @racket[call-with-composable-continuation] are sometimes
called @deftech{composable continuations}, because they do not have a called @deftech{composable continuations}, because they do not have a
built-in @tech{abort}. built-in @tech{abort}.
For an example of how @tech{continuations} are useful, see For an example of how @tech{continuations} are useful, see
@other-manual['(lib "scribblings/more/more.scrbl")]. For specific @other-manual['(lib "scribblings/more/more.scrbl")]. For specific
control operators that have more convenient names than the primitives control operators that have more convenient names than the primitives
described here, see @schememodname[scheme/control]. described here, see @racketmodname[racket/control].
@; ---------------------------------------------------------------------- @; ----------------------------------------------------------------------

View File

@ -1,28 +1,26 @@
#lang scribble/doc #lang scribble/base
@(require scribble/manual @(require scribble/manual
"guide-utils.ss") "guide-utils.ss")
@(define r6rs @elem{R@superscript{6}RS}) @(define r6rs @elem{R@superscript{6}RS})
@(define r5rs @elem{R@superscript{5}RS}) @(define r5rs @elem{R@superscript{5}RS})
@title[#:tag "dialects" #:style 'toc]{Dialects of Scheme} @title[#:tag "dialects" #:style 'toc]{Dialects of Racket and Scheme}
PLT Scheme is one dialect of the Scheme programming language, and We use ``Racket'' to refer to a specific dialect of the Lisp language,
there are many others. Indeed, ``Scheme'' is perhaps more of an idea and one that is based on the Scheme branch of the Lisp family.
than a specific language. Despite Racket's similarly to Scheme, the @hash-lang[] prefix on
modules is a particular feature of Racket, and programs that start
with @hash-lang[] are unlikely to run in other implementations of
Scheme. At the same time, programs that do not start with @hash-lang[]
do not work with the default mode of most Racket tools.
The @hash-lang[] prefix on modules is a particular feature of PLT ``Racket'' is not, however, the only dialect of Lisp that is supported
Scheme, and programs that start with @hash-lang[] are unlikely to run by Racket tools. On the contrary, Racket tools are designed to support
in other implementations of Scheme. At the same time, programs that do multiple dialects of Lisp and even multiple languages, which allows
not start with @hash-lang[] (or another PLT Scheme module form) do not the Racket tool suite to serve multiple communities. Racket also gives
work with the default mode of most PLT Scheme tools. programmers and researchers the tools they need to explore and create
new languages.
``PLT Scheme'' is not, however, the only dialect of Scheme that is supported
by PLT Scheme tools. On the contrary, PLT Scheme tools are designed to
support multiple dialects of Scheme and even multiple languages, which
allows the PLT Scheme tool suite to serve multiple communities. PLT
Scheme also gives programmers and researchers the tools they need to
explore and create new languages.
@local-table-of-contents[] @local-table-of-contents[]
@ -39,10 +37,10 @@ Standard dialects of Scheme include the ones defined by @|r5rs| and
Revised@superscript{5} Report on the Algorithmic Language Scheme}, and Revised@superscript{5} Report on the Algorithmic Language Scheme}, and
it is currently the most widely implemented Scheme standard. it is currently the most widely implemented Scheme standard.
PLT Scheme tools in their default modes do not conform to @|r5rs|, Racket tools in their default modes do not conform to @|r5rs|,
mainly because PLT Scheme tools generally expect modules, and @|r5rs| mainly because Racket tools generally expect modules, and @|r5rs|
does not define a module system. Typical single-file @|r5rs| programs does not define a module system. Typical single-file @|r5rs| programs
can be converted to PLT Scheme programs by prefixing them with can be converted to Racket programs by prefixing them with
@scheme[@#,hash-lang[] @#,schememodname[r5rs]], but other Scheme @scheme[@#,hash-lang[] @#,schememodname[r5rs]], but other Scheme
systems do not recognize @scheme[@#,hash-lang[] systems do not recognize @scheme[@#,hash-lang[]
@#,schememodname[r5rs]]. The @exec{plt-r5rs} executable (see @#,schememodname[r5rs]]. The @exec{plt-r5rs} executable (see
@ -50,106 +48,106 @@ systems do not recognize @scheme[@#,hash-lang[]
conforms to the @|r5rs| standard. conforms to the @|r5rs| standard.
Aside from the module system, the syntactic forms and functions of Aside from the module system, the syntactic forms and functions of
@|r5rs| and PLT Scheme differ. Only simple @|r5rs| become PLT Scheme @|r5rs| and Racket differ. Only simple @|r5rs| become Racket
programs when prefixed with @scheme[@#,hash-lang[] scheme], and programs when prefixed with @scheme[@#,hash-lang[] racket], and
relatively few PLT Scheme programs become @|r5rs| programs when a relatively few Racket programs become @|r5rs| programs when a
@hash-lang[] line is removed. Also, when mixing ``@|r5rs| modules'' @hash-lang[] line is removed. Also, when mixing ``@|r5rs| modules''
with PLT Scheme modules, beware that @|r5rs| pairs correspond to PLT with Racket modules, beware that @|r5rs| pairs correspond to
Scheme mutable pairs (as constructed with @scheme[mcons]). Racket mutable pairs (as constructed with @scheme[mcons]).
See @other-manual['(lib "r5rs/r5rs.scrbl")] for more See @other-manual['(lib "r5rs/r5rs.scrbl")] for more
information about running @|r5rs| programs with PLT Scheme. information about running @|r5rs| programs with Racket.
@subsection{@|r6rs|} @subsection{@|r6rs|}
``@|r6rs|'' stands for @link["../r6rs-std/index.html"]{The ``@|r6rs|'' stands for @link["../r6rs-std/index.html"]{The
Revised@superscript{6} Report on the Algorithmic Language Scheme}, Revised@superscript{6} Report on the Algorithmic Language Scheme},
which extends @|r5rs| with a module system that is similar to the PLT which extends @|r5rs| with a module system that is similar to the
Scheme module system. Racket module system.
When an @|r6rs| library or top-level program is prefixed with When an @|r6rs| library or top-level program is prefixed with
@schememetafont{#!}@schememodname[r6rs] (which is valid @|r6rs| @schememetafont{#!}@schememodname[r6rs] (which is valid @|r6rs|
syntax), then it can also be used as a PLT Scheme program. This works syntax), then it can also be used as a Racket program. This works
because @schememetafont{#!} in PLT Scheme is treated as a shorthand because @schememetafont{#!} in Racket is treated as a shorthand
for @hash-lang[] followed by a space, so for @hash-lang[] followed by a space, so
@schememetafont{#!}@schememodname[r6rs] selects the @schememetafont{#!}@schememodname[r6rs] selects the
@schememodname[r6rs] module language. As with @|r5rs|, however, beware @schememodname[r6rs] module language. As with @|r5rs|, however, beware
that the syntactic forms and functions of @|r6rs| differ from PLT that the syntactic forms and functions of @|r6rs| differ from
Scheme, and @|r6rs| pairs are mutable pairs. Racket, and @|r6rs| pairs are mutable pairs.
See @other-manual['(lib "r6rs/scribblings/r6rs.scrbl")] for more See @other-manual['(lib "r6rs/scribblings/r6rs.scrbl")] for more
information about running @|r6rs| programs with PLT Scheme. information about running @|r6rs| programs with Racket.
@; -------------------------------------------------- @; --------------------------------------------------
@section[#:tag "more-hash-lang"]{More PLT Schemes} @section[#:tag "more-hash-lang"]{More Rackets}
Like ``Scheme'' itself, even ``PLT Scheme'' is more of an idea about Like ``Scheme,'' even ``Racket'' is more of an idea about
programming languages than a language in the usual sense. Macros can programming languages than a language in the usual sense. Macros can
extend a base language (as described in @secref["macros"]), but macros extend a base language (as described in @secref["macros"]), but macros
and alternate parsers can construct an entirely new language from the and alternate parsers can construct an entirely new language from the
ground up. ground up.
The @hash-lang[] line that starts a PLT Scheme module declares the The @hash-lang[] line that starts a Racket module declares the
base language of the module. By ``PLT Scheme,'' we usually mean base language of the module. By ``Racket,'' we usually mean
@hash-lang[] followed by the base language @schememodname[scheme] or @hash-lang[] followed by the base language @racketmodname[racket] or
@schememodname[scheme/base] (of which @schememodname[scheme] is an @racketmodname[racket/base] (of which @racketmodname[racket] is an
extension). The PLT Scheme distribution provides additional languages, extension). The Racket distribution provides additional languages,
including the following: including the following:
@itemize[ @itemize[
@item{@schememodname[typed/scheme] --- like @item{@racketmodname[typed/scheme] --- like
@schememodname[scheme], but statically typed; see @racketmodname[racket], but statically typed; see
@other-manual['(lib "typed-scheme/scribblings/ts-guide.scrbl")]} @other-manual['(lib "typed-scheme/scribblings/ts-guide.scrbl")]}
@item{@schememodname[lazy] --- like @schememodname[scheme/base], but @item{@racketmodname[lazy] --- like @racketmodname[racket/base], but
avoids evaluating an expression until its value is needed; see avoids evaluating an expression until its value is needed; see
@other-manual['(lib "lazy/lazy.scrbl")]} @other-manual['(lib "lazy/lazy.scrbl")]}
@item{@schememodname[frtime] --- changes evaluation in an even more @item{@racketmodname[frtime] --- changes evaluation in an even more
radical way to support reactive programming; see radical way to support reactive programming; see
@other-manual['(lib "frtime/scribblings/frtime.scrbl")]} @other-manual['(lib "frtime/scribblings/frtime.scrbl")]}
@item{@schememodname[scribble/doc] --- a language, which looks more @item{@racketmodname[scribble/base] --- a language, which looks more
like Latex than Scheme, for writing documentation; see like Latex than Racket, for writing documentation; see
@other-manual['(lib "scribblings/scribble/scribble.scrbl")]} @other-manual['(lib "scribblings/scribble/scribble.scrbl")]}
] ]
Each of these languages is used by starting module with the language Each of these languages is used by starting module with the language
name after @hash-lang[]. For example, this source of this name after @hash-lang[]. For example, this source of this
document starts with @scheme[@#,hash-lang[] scribble/doc]. document starts with @racket[@#,hash-lang[] scribble/base].
PLT Scheme users can define their own languages. A language name maps Racket users can define their own languages. A language name maps
to its implementation through a module path by adding to its implementation through a module path by adding
@schemeidfont{/lang/reader}. For example, the language name @racketidfont{/lang/reader}. For example, the language name
@schememodname[scribble/doc] is expanded to @racketmodname[scribble/doc] is expanded to
@scheme[scribble/doc/lang/reader], which is the module that implements @racket[scribble/doc/lang/reader], which is the module that implements
the surface-syntax parser. The parser, in turn, generates a the surface-syntax parser. The parser, in turn, generates a
@scheme[module] form, which determines the base language at the level @racket[module] form, which determines the base language at the level
of syntactic forms an functions. of syntactic forms an functions.
Some language names act as language loaders. For example, Some language names act as language loaders. For example,
@schememodname[s-exp] as a language uses the usual PLT Scheme parser @racketmodname[s-exp] as a language uses the usual Racket parser
for surface-syntax reading, and then it uses the module path after for surface-syntax reading, and then it uses the module path after
@schememodname[s-exp] for the language's syntactic forms. Thus, @racketmodname[s-exp] for the language's syntactic forms. Thus,
@scheme[@#,hash-lang[] @#,schememodname[s-exp] "mylang.ss"] parses @racket[@#,hash-lang[] @#,racketmodname[s-exp] "mylang.rkt"] parses
the module body using the normal PLT Scheme reader, by then imports the module body using the normal Racket reader, by then imports
the initial syntax and functions for the module body from the initial syntax and functions for the module body from
@scheme["mylang.ss"]. Similarly, @scheme[@#,hash-lang[] @racket["mylang.rkt"]. Similarly, @racket[@#,hash-lang[]
@#,schememodname[planet] _planet-path] loads a language via @#,racketmodname[planet] _planet-path] loads a language via
@seclink["top" #:doc '(lib "planet/planet.scrbl")]{@|PLaneT|}. @seclink["top" #:doc '(lib "planet/planet.scrbl")]{@|PLaneT|}.
@; -------------------------------------------------- @; --------------------------------------------------
@section[#:tag "teaching-langs"]{Teaching} @section[#:tag "teaching-langs"]{Teaching}
The @|HtDP| textbook relies on pedagogic variants of Scheme that The @|HtDP| textbook relies on pedagogic variants of Racket that
smooth the introduction of programming concepts for new programmers. smooth the introduction of programming concepts for new programmers.
The languages are documented in @other-manual['(lib The languages are documented in @other-manual['(lib
"scribblings/htdp-langs/htdp-langs.scrbl")]. "scribblings/htdp-langs/htdp-langs.scrbl")].
The @|HtDP| languages are typically not used with @hash-lang[] The @|HtDP| languages are typically not used with @hash-lang[]
prefixes, but are instead used within DrScheme by selecting the prefixes, but are instead used within DrRacket by selecting the
language from the @onscreen{Choose Language...} dialog. language from the @onscreen{Choose Language...} dialog.

View File

@ -5,24 +5,24 @@
@title[#:tag "for"]{Iterations and Comprehensions} @title[#:tag "for"]{Iterations and Comprehensions}
The @scheme[for] family of syntactic forms support iteration over The @racket[for] family of syntactic forms support iteration over
@defterm{sequences}. Lists, vectors, strings, byte strings, input @defterm{sequences}. Lists, vectors, strings, byte strings, input
ports, and hash tables can all be used as sequences, and constructors ports, and hash tables can all be used as sequences, and constructors
like @scheme[in-range] offer even more kinds of sequences. like @racket[in-range] offer even more kinds of sequences.
Variants of @scheme[for] accumulate iteration results in different Variants of @racket[for] accumulate iteration results in different
ways, but they all have the same syntactic shape. Simplifying for ways, but they all have the same syntactic shape. Simplifying for
now, the syntax of @scheme[for] is now, the syntax of @racket[for] is
@specform[ @specform[
(for ([id sequence-expr] ...) (for ([id sequence-expr] ...)
body ...+) body ...+)
]{} ]{}
A @scheme[for] loop iterates through the sequence produced by the A @racket[for] loop iterates through the sequence produced by the
@scheme[_sequence-expr]. For each element of the sequence, @racket[_sequence-expr]. For each element of the sequence,
@scheme[for] binds the element to @scheme[_id], and then it evaluates @racket[for] binds the element to @racket[_id], and then it evaluates
the @scheme[_body]s for side effects. the @racket[_body]s for side effects.
@examples[ @examples[
(for ([i '(1 2 3)]) (for ([i '(1 2 3)])
@ -31,10 +31,10 @@ the @scheme[_body]s for side effects.
(printf "~a..." i)) (printf "~a..." i))
] ]
The @scheme[for/list] variant of @scheme[for] is more Scheme-like. It The @racket[for/list] variant of @racket[for] is more Racket-like. It
accumulates @scheme[_body] results into a list, instead of accumulates @racket[_body] results into a list, instead of
evaluating @scheme[_body] only for side effects. In more evaluating @racket[_body] only for side effects. In more
technical terms, @scheme[for/list] implements a @defterm{list technical terms, @racket[for/list] implements a @defterm{list
comprehension}. comprehension}.
@examples[ @examples[
@ -44,22 +44,22 @@ comprehension}.
i) i)
] ]
The full syntax of @scheme[for] accommodates multiple sequences to The full syntax of @racket[for] accommodates multiple sequences to
iterate in parallel, and the @scheme[for*] variant nests the iterate in parallel, and the @racket[for*] variant nests the
iterations instead of running them in parallel. More variants of iterations instead of running them in parallel. More variants of
@scheme[for] and @scheme[for*] accumulate @scheme[_body] results @racket[for] and @racket[for*] accumulate @racket[_body] results
in different ways. In all of these variants, predicates that prune in different ways. In all of these variants, predicates that prune
iterations can be included along with bindings. iterations can be included along with bindings.
Before details on the variations of @scheme[for], though, it's best to Before details on the variations of @racket[for], though, it's best to
see the kinds of sequence generators that make interesting examples. see the kinds of sequence generators that make interesting examples.
@section[#:tag "sequences"]{Sequence Constructors} @section[#:tag "sequences"]{Sequence Constructors}
The @scheme[in-range] function generates a sequence of numbers, given The @racket[in-range] function generates a sequence of numbers, given
an optional starting number (which defaults to @scheme[0]), a number an optional starting number (which defaults to @racket[0]), a number
before which the sequences ends, and an optional step (which defaults before which the sequences ends, and an optional step (which defaults
to @scheme[1]). to @racket[1]).
@examples[ @examples[
(for ([i (in-range 3)]) (for ([i (in-range 3)])
@ -74,10 +74,10 @@ to @scheme[1]).
(printf " ~a " i)) (printf " ~a " i))
] ]
The @scheme[in-naturals] function is similar, except that the The @racket[in-naturals] function is similar, except that the
starting number must be an exact non-negative integer (which defaults starting number must be an exact non-negative integer (which defaults
to @scheme[0]), the step is always @scheme[1], and there is no upper to @racket[0]), the step is always @racket[1], and there is no upper
limit. A @scheme[for] loop using just @scheme[in-naturals] will never limit. A @racket[for] loop using just @racket[in-naturals] will never
terminate unless a body expression raises an exception or otherwise terminate unless a body expression raises an exception or otherwise
escapes. escapes.
@ -88,7 +88,7 @@ escapes.
(display i))) (display i)))
] ]
The @scheme[stop-before] and @scheme[stop-after] functions construct The @racket[stop-before] and @racket[stop-after] functions construct
a new sequence given a sequence and a predicate. The new sequence is a new sequence given a sequence and a predicate. The new sequence is
like the given sequence, but truncated either immediately before or like the given sequence, but truncated either immediately before or
immediately after the first element for which the predicate returns immediately after the first element for which the predicate returns
@ -100,8 +100,8 @@ true.
(display i)) (display i))
] ]
Sequence constructors like @scheme[in-list], @scheme[in-vector] and Sequence constructors like @racket[in-list], @racket[in-vector] and
@scheme[in-string] simply make explicit the use of a list, vector, or @racket[in-string] simply make explicit the use of a list, vector, or
string as a sequence. Since they raise an exception when given the string as a sequence. Since they raise an exception when given the
wrong kind of value, and since they otherwise avoid a run-time wrong kind of value, and since they otherwise avoid a run-time
dispatch to determine the sequence type, they enable more efficient dispatch to determine the sequence type, they enable more efficient
@ -116,9 +116,9 @@ code generation; see @secref["for-performance"] for more information.
@refdetails["sequences"]{sequences} @refdetails["sequences"]{sequences}
@section{@scheme[for] and @scheme[for*]} @section{@racket[for] and @racket[for*]}
A more complete syntax of @scheme[for] is A more complete syntax of @racket[for] is
@specform/subs[ @specform/subs[
(for (clause ...) (for (clause ...)
@ -127,8 +127,8 @@ A more complete syntax of @scheme[for] is
(code:line #:when boolean-expr)]) (code:line #:when boolean-expr)])
]{} ]{}
When multiple @scheme[[_id _sequence-expr]] clauses are provided When multiple @racket[[_id _sequence-expr]] clauses are provided
in a @scheme[for] form, the corresponding sequences are traversed in in a @racket[for] form, the corresponding sequences are traversed in
parallel: parallel:
@interaction[ @interaction[
@ -137,8 +137,8 @@ parallel:
(printf "Chapter ~a. ~a\n" i chapter)) (printf "Chapter ~a. ~a\n" i chapter))
] ]
With parallel sequences, the @scheme[for] expression stops iterating With parallel sequences, the @racket[for] expression stops iterating
when any sequence ends. This behavior allows @scheme[in-naturals], when any sequence ends. This behavior allows @racket[in-naturals],
which creates an infinite sequence of numbers, to be used for which creates an infinite sequence of numbers, to be used for
indexing: indexing:
@ -148,7 +148,7 @@ indexing:
(printf "Chapter ~a. ~a\n" i chapter)) (printf "Chapter ~a. ~a\n" i chapter))
] ]
The @scheme[for*] form, which has the same syntax as @scheme[for], The @racket[for*] form, which has the same syntax as @racket[for],
nests multiple sequences instead of running them in parallel: nests multiple sequences instead of running them in parallel:
@interaction[ @interaction[
@ -157,12 +157,12 @@ nests multiple sequences instead of running them in parallel:
(printf "~a ~a\n" book chapter)) (printf "~a ~a\n" book chapter))
] ]
Thus, @scheme[for*] is a shorthand for nested @scheme[for]s in the Thus, @racket[for*] is a shorthand for nested @racket[for]s in the
same way that @scheme[let*] is a shorthand for nested @scheme[let]s. same way that @racket[let*] is a shorthand for nested @racket[let]s.
The @scheme[#:when _boolean-expr] form of a @scheme[_clause] is The @racket[#:when _boolean-expr] form of a @racket[_clause] is
another shorthand. It allows the @scheme[_body]s to evaluate only another shorthand. It allows the @racket[_body]s to evaluate only
when the @scheme[_boolean-expr] produces a true value: when the @racket[_boolean-expr] produces a true value:
@interaction[ @interaction[
(for* ([book '("Guide" "Reference")] (for* ([book '("Guide" "Reference")]
@ -171,11 +171,11 @@ when the @scheme[_boolean-expr] produces a true value:
(printf "~a ~a\n" book chapter)) (printf "~a ~a\n" book chapter))
] ]
A @scheme[_boolean-expr] with @scheme[#:when] can refer to any of the A @racket[_boolean-expr] with @racket[#:when] can refer to any of the
preceding iteration bindings. In a @scheme[for] form, this scoping preceding iteration bindings. In a @racket[for] form, this scoping
makes sense only if the test is nested in the iteration of the makes sense only if the test is nested in the iteration of the
preceding bindings; thus, bindings separated by @scheme[#:when] are preceding bindings; thus, bindings separated by @racket[#:when] are
mutually nested, instead of in parallel, even with @scheme[for]. mutually nested, instead of in parallel, even with @racket[for].
@interaction[ @interaction[
(for ([book '("Guide" "Reference" "Notes")] (for ([book '("Guide" "Reference" "Notes")]
@ -186,10 +186,10 @@ mutually nested, instead of in parallel, even with @scheme[for].
(printf "~a Chapter ~a. ~a\n" book i chapter)) (printf "~a Chapter ~a. ~a\n" book i chapter))
] ]
@section{@scheme[for/list] and @scheme[for*/list]} @section{@racket[for/list] and @racket[for*/list]}
The @scheme[for/list] form, which has the same syntax as @scheme[for], The @racket[for/list] form, which has the same syntax as @racket[for],
evaluates the @scheme[_body]s to obtain values that go into a evaluates the @racket[_body]s to obtain values that go into a
newly constructed list: newly constructed list:
@interaction[ @interaction[
@ -198,8 +198,8 @@ newly constructed list:
(string-append (number->string i) ". " chapter)) (string-append (number->string i) ". " chapter))
] ]
A @scheme[#:when] clause in a @scheme[for-list] form prunes the result A @racket[#:when] clause in a @racket[for-list] form prunes the result
list along with evaluations of the @scheme[_body]s: list along with evaluations of the @racket[_body]s:
@interaction[ @interaction[
(for/list ([i (in-naturals 1)] (for/list ([i (in-naturals 1)]
@ -208,13 +208,13 @@ list along with evaluations of the @scheme[_body]s:
chapter) chapter)
] ]
This pruning behavior of @scheme[#:when] is more useful with This pruning behavior of @racket[#:when] is more useful with
@scheme[for/list] than @scheme[for]. Whereas a plain @scheme[when] @racket[for/list] than @racket[for]. Whereas a plain @racket[when]
form normally suffices with @scheme[for], a @scheme[when] expression form normally suffices with @racket[for], a @racket[when] expression
form in a @scheme[for/list] would cause the result list to contain form in a @racket[for/list] would cause the result list to contain
@|void-const|s instead of omitting list elements. @|void-const|s instead of omitting list elements.
The @scheme[for*/list] is like @scheme[for*], nesting multiple The @racket[for*/list] is like @racket[for*], nesting multiple
iterations: iterations:
@interaction[ @interaction[
@ -223,23 +223,23 @@ iterations:
(string-append book " " chapter)) (string-append book " " chapter))
] ]
A @scheme[for*/list] form is not quite the same thing as nested A @racket[for*/list] form is not quite the same thing as nested
@scheme[for/list] forms. Nested @scheme[for/list]s would produce a @racket[for/list] forms. Nested @racket[for/list]s would produce a
list of lists, instead of one flattened list. Much like list of lists, instead of one flattened list. Much like
@scheme[#:when], then, the nesting of @scheme[for*/list] is more @racket[#:when], then, the nesting of @racket[for*/list] is more
useful than the nesting of @scheme[for*]. useful than the nesting of @racket[for*].
@section{@scheme[for/and] and @scheme[for/or]} @section{@racket[for/and] and @racket[for/or]}
The @scheme[for/and] form combines iteration results with The @racket[for/and] form combines iteration results with
@scheme[and], stopping as soon as it encounters @scheme[#f]: @racket[and], stopping as soon as it encounters @racket[#f]:
@interaction[ @interaction[
(for/and ([chapter '("Intro" "Details" "Conclusion")]) (for/and ([chapter '("Intro" "Details" "Conclusion")])
(equal? chapter "Intro")) (equal? chapter "Intro"))
] ]
The @scheme[for/or] form combines iteration results with @scheme[or], The @racket[for/or] form combines iteration results with @racket[or],
stopping as soon as it encounters a true value: stopping as soon as it encounters a true value:
@interaction[ @interaction[
@ -247,14 +247,14 @@ stopping as soon as it encounters a true value:
(equal? chapter "Intro")) (equal? chapter "Intro"))
] ]
As usual, the @scheme[for*/and] and @scheme[for*/or] forms provide the As usual, the @racket[for*/and] and @racket[for*/or] forms provide the
same facility with nested iterations. same facility with nested iterations.
@section{@scheme[for/first] and @scheme[for/last]} @section{@racket[for/first] and @racket[for/last]}
The @scheme[for/first] form returns the result of the first time that The @racket[for/first] form returns the result of the first time that
the @scheme[_body]s are evaluated, skipping further iterations. the @racket[_body]s are evaluated, skipping further iterations.
This form is most useful with a @scheme[#:when] clause. This form is most useful with a @racket[#:when] clause.
@interaction[ @interaction[
(for/first ([chapter '("Intro" "Details" "Conclusion" "Index")] (for/first ([chapter '("Intro" "Details" "Conclusion" "Index")]
@ -262,11 +262,11 @@ This form is most useful with a @scheme[#:when] clause.
chapter) chapter)
] ]
If the @scheme[_body]s are evaluated zero times, then the result If the @racket[_body]s are evaluated zero times, then the result
is @scheme[#f]. is @racket[#f].
The @scheme[for/last] form runs all iterations, returning the value of The @racket[for/last] form runs all iterations, returning the value of
the last iteration (or @scheme[#f] if no iterations are run): the last iteration (or @racket[#f] if no iterations are run):
@interaction[ @interaction[
(for/last ([chapter '("Intro" "Details" "Conclusion" "Index")] (for/last ([chapter '("Intro" "Details" "Conclusion" "Index")]
@ -274,7 +274,7 @@ the last iteration (or @scheme[#f] if no iterations are run):
chapter) chapter)
] ]
As usual, the @scheme[for*/first] and @scheme[for*/last] forms provide As usual, the @racket[for*/first] and @racket[for*/last] forms provide
the same facility with nested iterations: the same facility with nested iterations:
@interaction[ @interaction[
@ -289,26 +289,26 @@ the same facility with nested iterations:
(list book chapter)) (list book chapter))
] ]
@section[#:tag "for/fold"]{@scheme[for/fold] and @scheme[for*/fold]} @section[#:tag "for/fold"]{@racket[for/fold] and @racket[for*/fold]}
The @scheme[for/fold] form is a very general way to combine iteration The @racket[for/fold] form is a very general way to combine iteration
results. Its syntax is slightly different than the syntax of results. Its syntax is slightly different than the syntax of
@scheme[for], because accumulation variables must be declared at the @racket[for], because accumulation variables must be declared at the
beginning: beginning:
@schemeblock[ @racketblock[
(for/fold ([_accum-id _init-expr] ...) (for/fold ([_accum-id _init-expr] ...)
(_clause ...) (_clause ...)
_body ...+) _body ...+)
] ]
In the simple case, only one @scheme[[_accum-id _init-expr]] is In the simple case, only one @racket[[_accum-id _init-expr]] is
provided, and the result of the @scheme[for/fold] is the final value provided, and the result of the @racket[for/fold] is the final value
for @scheme[_accum-id], which starts out with the value of for @racket[_accum-id], which starts out with the value of
@scheme[_init-expr]. In the @scheme[_clause]s and @racket[_init-expr]. In the @racket[_clause]s and
@scheme[_body]s, @scheme[_accum-id] can be referenced to get its @racket[_body]s, @racket[_accum-id] can be referenced to get its
current value, and the last @scheme[_body] provides the value of current value, and the last @racket[_body] provides the value of
@scheme[_accum-id] for the next iteration. @racket[_accum-id] for the next iteration.
@examples[ @examples[
(for/fold ([len 0]) (for/fold ([len 0])
@ -322,9 +322,9 @@ current value, and the last @scheme[_body] provides the value of
chapter) chapter)
] ]
When multiple @scheme[_accum-id]s are specified, then the last When multiple @racket[_accum-id]s are specified, then the last
@scheme[_body] must produce multiple values, one for each @racket[_body] must produce multiple values, one for each
@scheme[_accum-id]. The @scheme[for/fold] expression itself produces @racket[_accum-id]. The @racket[for/fold] expression itself produces
multiple values for the results. multiple values for the results.
@examples[ @examples[
@ -344,12 +344,12 @@ values, individual iterations of a sequence can produce multiple
elements. For example, a hash table as a sequence generates two elements. For example, a hash table as a sequence generates two
values for each iteration: a key and a value. values for each iteration: a key and a value.
In the same way that @scheme[let-values] binds multiple results to In the same way that @racket[let-values] binds multiple results to
multiple identifiers, @scheme[for] can bind multiple sequence elements multiple identifiers, @racket[for] can bind multiple sequence elements
to multiple iteration identifiers: to multiple iteration identifiers:
@margin-note{While @scheme[let] must be changed to @scheme[let-values] @margin-note{While @racket[let] must be changed to @racket[let-values]
to bind multiple identifier, @scheme[for] simply allows a to bind multiple identifier, @racket[for] simply allows a
parenthesized list of identifiers instead of a single parenthesized list of identifiers instead of a single
identifier in any clause.} identifier in any clause.}
@ -358,8 +358,8 @@ to multiple iteration identifiers:
(printf "~a count: ~a\n" k v)) (printf "~a count: ~a\n" k v))
] ]
This extension to multiple-value bindings works for all @scheme[for] This extension to multiple-value bindings works for all @racket[for]
variants. For example, @scheme[for*/list] nests iterations, builds a variants. For example, @racket[for*/list] nests iterations, builds a
list, and also works with multiple-valued sequences: list, and also works with multiple-valued sequences:
@interaction[ @interaction[
@ -371,26 +371,26 @@ list, and also works with multiple-valued sequences:
@section[#:tag "for-performance"]{Iteration Performance} @section[#:tag "for-performance"]{Iteration Performance}
Ideally, a @scheme[for] iteration should run as fast as a loop that Ideally, a @racket[for] iteration should run as fast as a loop that
you write by hand as a recursive-function invocation. A hand-written you write by hand as a recursive-function invocation. A hand-written
loop, however, is normally specific to a particular kind of data, such loop, however, is normally specific to a particular kind of data, such
as lists. In that case, the hand-written loop uses selectors like as lists. In that case, the hand-written loop uses selectors like
@scheme[car] and @scheme[cdr] directly, instead of handling all forms @racket[car] and @racket[cdr] directly, instead of handling all forms
of sequences and dispatching to an appropriate iterator. of sequences and dispatching to an appropriate iterator.
The @scheme[for] forms can provide the performance of hand-written The @racket[for] forms can provide the performance of hand-written
loops when enough information is apparent about the sequences to loops when enough information is apparent about the sequences to
iterate. Specifically, the clause should have one of the following iterate. Specifically, the clause should have one of the following
@scheme[_fast-clause] forms: @racket[_fast-clause] forms:
@schemegrammar[ @racketgrammar[
fast-clause [id fast-seq] fast-clause [id fast-seq]
[(id) fast-seq] [(id) fast-seq]
[(id id) fast-indexed-seq] [(id id) fast-indexed-seq]
[(id ...) fast-parallel-seq] [(id ...) fast-parallel-seq]
] ]
@schemegrammar[ @racketgrammar[
#:literals [in-range in-naturals in-list in-vector in-string in-bytes in-value stop-before stop-after] #:literals [in-range in-naturals in-list in-vector in-string in-bytes in-value stop-before stop-after]
fast-seq (in-range expr expr) fast-seq (in-range expr expr)
(in-range expr expr expr) (in-range expr expr expr)
@ -405,14 +405,14 @@ fast-seq (in-range expr expr)
(stop-after fast-seq predicate-expr) (stop-after fast-seq predicate-expr)
] ]
@schemegrammar[ @racketgrammar[
#:literals [in-indexed stop-before stop-after] #:literals [in-indexed stop-before stop-after]
fast-indexed-seq (in-indexed fast-seq) fast-indexed-seq (in-indexed fast-seq)
(stop-before fast-indexed-seq predicate-expr) (stop-before fast-indexed-seq predicate-expr)
(stop-after fast-indexed-seq predicate-expr) (stop-after fast-indexed-seq predicate-expr)
] ]
@schemegrammar[ @racketgrammar[
#:literals [in-parallel stop-before stop-after] #:literals [in-parallel stop-before stop-after]
fast-parallel-seq (in-parallel fast-seq ...) fast-parallel-seq (in-parallel fast-seq ...)
(stop-before fast-parallel-seq predicate-expr) (stop-before fast-parallel-seq predicate-expr)
@ -436,6 +436,6 @@ The grammars above are not complete, because the set of syntactic
patterns that provide good performance is extensible, just like the patterns that provide good performance is extensible, just like the
set of sequence values. The documentation for a sequence constructor set of sequence values. The documentation for a sequence constructor
should indicate the performance benefits of using it directly in should indicate the performance benefits of using it directly in
a @scheme[for] @scheme[_clause]. a @racket[for] @racket[_clause].
@refdetails["for"]{iterations and comprehensions} @refdetails["for"]{iterations and comprehensions}

View File

@ -4,22 +4,24 @@
scribble/eval scribble/eval
mzlib/process mzlib/process
"guide-utils.ss" "guide-utils.ss"
(for-label scheme/tcp (for-label racket/tcp
scheme/serialize racket/serialize
scheme/port)) racket/port))
@(define io-eval (make-base-eval)) @(define io-eval (make-base-eval))
@(define (twocolumn a b) @(define (threecolumn a b c)
(make-table #f (make-table #f
(list (list (make-flow (list a)) (list (list (make-flow (list a))
(make-flow (list (make-paragraph (list (hspace 1))))) (make-flow (list (make-paragraph (list (hspace 1)))))
(make-flow (list b)))))) (make-flow (list b))
(make-flow (list (make-paragraph (list (hspace 1)))))
(make-flow (list c))))))
@(interaction-eval #:eval io-eval (print-hash-table #t)) @(interaction-eval #:eval io-eval (print-hash-table #t))
@title[#:tag "i/o" #:style 'toc]{Input and Output} @title[#:tag "i/o" #:style 'toc]{Input and Output}
A Scheme @deftech{port} represents an input or output stream, such as A Racket @deftech{port} represents an input or output stream, such as
a file, a terminal, a TCP connection, or an in-memory string. More a file, a terminal, a TCP connection, or an in-memory string. More
specifically, an @defterm{input port} represents a stream from which a specifically, an @defterm{input port} represents a stream from which a
program can read data, and an @defterm{output port} represents a program can read data, and an @defterm{output port} represents a
@ -28,7 +30,7 @@ stream for writing data.
@local-table-of-contents[] @local-table-of-contents[]
@;------------------------------------------------------------------------ @;------------------------------------------------------------------------
@section{Varieties of Ports} @section[#:tag "ports"]{Varieties of Ports}
Various functions create various kinds of ports. Here are a few Various functions create various kinds of ports. Here are a few
examples: examples:
@ -36,8 +38,8 @@ examples:
@itemize[ @itemize[
@;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@item{@bold{Files:} The @scheme[open-output-file] function opens a @item{@bold{Files:} The @racket[open-output-file] function opens a
file for writing, and @scheme[open-input-file] opens a file for file for writing, and @racket[open-input-file] opens a file for
reading. reading.
@(interaction-eval #:eval io-eval (define old-dir (current-directory))) @(interaction-eval #:eval io-eval (define old-dir (current-directory)))
@ -54,9 +56,9 @@ examples:
(close-input-port in) (close-input-port in)
] ]
If a file exists already, then @scheme[open-output-file] raises an If a file exists already, then @racket[open-output-file] raises an
exception by default. Supply an option like @scheme[#:exists exception by default. Supply an option like @racket[#:exists
'truncate] or @scheme[#:exists 'update] to re-write or update the 'truncate] or @racket[#:exists 'update] to re-write or update the
file: file:
@examples[ @examples[
@ -66,9 +68,9 @@ file:
(close-output-port out) (close-output-port out)
] ]
Instead of having to match @scheme[open-input-file] and Instead of having to match @racket[open-input-file] and
@scheme[open-output-file] calls, most Scheme programmers will instead @racket[open-output-file] calls, most Racket programmers will instead
use @scheme[call-with-output-file], which takes a function to call use @racket[call-with-output-file], which takes a function to call
with the output port; when the function returns, the port is closed. with the output port; when the function returns, the port is closed.
@examples[ @examples[
@ -86,9 +88,9 @@ with the output port; when the function returns, the port is closed.
@(interaction-eval #:eval io-eval (current-directory old-dir))} @(interaction-eval #:eval io-eval (current-directory old-dir))}
@;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@item{@bold{Strings:} The @scheme[open-output-string] function creates @item{@bold{Strings:} The @racket[open-output-string] function creates
a port that accumulates data into a string, and @scheme[get-output-string] a port that accumulates data into a string, and @racket[get-output-string]
extracts the accumulated string. The @scheme[open-input-string] function extracts the accumulated string. The @racket[open-input-string] function
creates a port to read from a string. creates a port to read from a string.
@examples[ @examples[
@ -101,10 +103,10 @@ with the output port; when the function returns, the port is closed.
@;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@item{@bold{TCP Connections:} The @scheme[tcp-connect] function @item{@bold{TCP Connections:} The @racket[tcp-connect] function
creates both an input port and an output port for the client side of creates both an input port and an output port for the client side of
a TCP communication. The @scheme[tcp-listen] function creates a a TCP communication. The @racket[tcp-listen] function creates a
server, which accepts connections via @scheme[tcp-accept]. server, which accepts connections via @racket[tcp-accept].
@examples[ @examples[
#:eval io-eval #:eval io-eval
@ -121,7 +123,7 @@ with the output port; when the function returns, the port is closed.
@;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@item{@bold{Process Pipes:} The @scheme[subprocess] function runs a new @item{@bold{Process Pipes:} The @racket[subprocess] function runs a new
process at the OS level and returns ports that correspond to the process at the OS level and returns ports that correspond to the
subprocess's stdin, stdout, and stderr. (The first three arguments subprocess's stdin, stdout, and stderr. (The first three arguments
can be certain kinds of existing ports to connect directly to the can be certain kinds of existing ports to connect directly to the
@ -143,9 +145,9 @@ with the output port; when the function returns, the port is closed.
@;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - @;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
@item{@bold{Internal Pipes:} The @scheme[make-pipe] function returns @item{@bold{Internal Pipes:} The @racket[make-pipe] function returns
two ports that are ends of a pipe. This kind of pipe is internal to two ports that are ends of a pipe. This kind of pipe is internal to
Scheme, and not related to OS-level pipes for communicating between Racket, and not related to OS-level pipes for communicating between
different processes. different processes.
@examples[ @examples[
@ -159,14 +161,14 @@ with the output port; when the function returns, the port is closed.
] ]
@;------------------------------------------------------------------------ @;------------------------------------------------------------------------
@section{Default Ports} @section[#:tag "default-ports"]{Default Ports}
For most simple I/O functions, the target port is an optional For most simple I/O functions, the target port is an optional
argument, and the default is the @defterm{current input port} or argument, and the default is the @defterm{current input port} or
@defterm{current output port}. Furthermore, error messages are written @defterm{current output port}. Furthermore, error messages are written
to the @defterm{current error port}, which is an output port. The to the @defterm{current error port}, which is an output port. The
@scheme[current-input-port], @scheme[current-output-port], and @racket[current-input-port], @racket[current-output-port], and
@scheme[current-error-port] functions return the corresponding current @racket[current-error-port] functions return the corresponding current
ports. ports.
@examples[ @examples[
@ -175,7 +177,7 @@ ports.
(code:line (display "Hi" (current-output-port)) (code:comment @#,t{the same})) (code:line (display "Hi" (current-output-port)) (code:comment @#,t{the same}))
] ]
If you start the @exec{mzscheme} program in a terminal, then the If you start the @exec{racket} program in a terminal, then the
current input, output, and error ports are all connected to the current input, output, and error ports are all connected to the
terminal. More generally, they are connected to the OS-level stdin, terminal. More generally, they are connected to the OS-level stdin,
stdout, and stderr. In this guide, the examples show output written to stdout, and stderr. In this guide, the examples show output written to
@ -188,8 +190,10 @@ stdout in purple, and output written to stderr in red italics.
(swing-hammer) (swing-hammer)
] ]
The current-port functions are actually parameters, which means that The current-port functions are actually @tech{parameters}, which means
their values can be set with @scheme[parameterize]. that their values can be set with @racket[parameterize].
@margin-note{See @secref["parameterize"] for an introduction to parameters.}
@examples[ @examples[
#:eval io-eval #:eval io-eval
@ -202,34 +206,47 @@ their values can be set with @scheme[parameterize].
] ]
@; ---------------------------------------------------------------------- @; ----------------------------------------------------------------------
@section{Reading and Writing Scheme Data} @section[#:tag "read-write"]{Reading and Writing Racket Data}
As noted throughout @secref["datatypes"], Scheme provides two As noted throughout @secref["datatypes"], Racket provides three
ways to print an instance of a built-in value: ways to print an instance of a built-in value:
@itemize[ @itemize[
@item{ @scheme[write], which prints a value in the same way that is it @item{@racket[print], which prints a value in the same way that is it
printed for a @tech{REPL} result; and } printed for a @tech{REPL} result; and }
@item{@scheme[display], which tends to reduce a value to just its @item{@racket[write], which prints a value in such a way that
@racket[read] on the output produces the value back; and }
@item{@racket[display], which tends to reduce a value to just its
character or byte content---at least for those datatypes that character or byte content---at least for those datatypes that
are primarily about characters or bytes, otherwise it falls are primarily about characters or bytes, otherwise it falls
back to the same output as @scheme[write].} back to the same output as @racket[write].}
] ]
Here are some examples using each: Here are some examples using each:
@twocolumn[ @threecolumn[
@interaction[
(print 1/2)
(print #\x)
(print "hello")
(print #"goodbye")
(print '|pea pod|)
(print '("i" pod))
(print write)
]
@interaction[ @interaction[
(write 1/2) (write 1/2)
(write #\x) (write #\x)
(write "hello") (write "hello")
(write #"goodbye") (write #"goodbye")
(write '|dollar sign|) (write '|pea pod|)
(write '("alphabet" soup)) (write '("i" pod))
(write write) (write write)
] ]
@ -238,27 +255,35 @@ Here are some examples using each:
(display #\x) (display #\x)
(display "hello") (display "hello")
(display #"goodbye") (display #"goodbye")
(display '|dollar sign|) (display '|pea pod|)
(display '("alphabet" soup)) (display '("i" pod))
(display write) (display write)
] ]
] ]
The @scheme[printf] function supports simple formatting of data and Overall, @racket[print] as corresponds to the expression layer of
text. In the format string supplied to @scheme[printf], @litchar{~a} Racket syntax, @racket[write] corresponds to the reader layer, and
@scheme[display]s the next argument, while @litchar{~s} @racket[display] roughly corresponds to the character layer.
@scheme[write]s the next argument.
The @racket[printf] function supports simple formatting of data and
text. In the format string supplied to @racket[printf], @litchar{~a}
@racket[display]s the next argument, @litchar{~s}
@racket[write]s the next argument, and @litchar{~v}
@racket[print]s the next argument.
@defexamples[ @defexamples[
#:eval io-eval #:eval io-eval
(define (deliver who what) (define (deliver who when what)
(printf "Value for ~a: ~s" who what)) (printf "Items ~a for shopper ~s: ~v" who when what))
(deliver "John" "string") (deliver '("list") '("John") '("milk"))
] ]
An advantage of @scheme[write], as opposed to @scheme[display], is After using @racket[write], as opposed to @racket[display] or
that many forms of data can be read back in using @scheme[read]. @racket[print], many forms of data can be read back in using
@racket[read]. The same values @racket[print]ed can also be parsed by
@scheme[read], but the result may have extra quote forms, since a
@racket[print]ed form is meant to be read like an expression.
@examples[ @examples[
#:eval io-eval #:eval io-eval
@ -269,6 +294,8 @@ that many forms of data can be read back in using @scheme[read].
(read in) (read in)
(write #hash((a . "apple") (b . "banana")) out) (write #hash((a . "apple") (b . "banana")) out)
(read in) (read in)
(write '("alphabet" soup) out)
(read in)
] ]
@; ---------------------------------------------------------------------- @; ----------------------------------------------------------------------
@ -284,100 +311,99 @@ an output stream, and a copy can be read back in from an input stream:
(read in) (read in)
] ]
Other structure types created by @scheme[define-struct], which offer Other structure types created by @racket[struct], which offer
more abstraction than @tech{prefab} structure types, normally more abstraction than @tech{prefab} structure types, normally
@scheme[write] either using @schemeresultfont{#<....>} notation (for @racket[write] either using @racketresultfont{#<....>} notation (for
opaque structure types) or using @schemeresultfont{#(....)} vector opaque structure types) or using @racketresultfont{#(....)} vector
notation (for transparent structure types). In neither can can the notation (for transparent structure types). In neither can can the
result be read back in as an instance of the structure type: result be read back in as an instance of the structure type:
@interaction[ @interaction[
(define-struct posn (x y)) (struct posn (x y))
(write (make-posn 1 2)) (write (posn 1 2))
(define-values (in out) (make-pipe)) (define-values (in out) (make-pipe))
(write (make-posn 1 2) out) (write (posn 1 2) out)
(read in) (read in)
] ]
@interaction[ @interaction[
(define-struct posn (x y) #:transparent) (struct posn (x y) #:transparent)
(write (make-posn 1 2)) (write (posn 1 2))
(define-values (in out) (make-pipe)) (define-values (in out) (make-pipe))
(write (make-posn 1 2) out) (write (posn 1 2) out)
(define v (read in)) (define v (read in))
v v
(posn? v) (posn? v)
(vector? v) (vector? v)
] ]
The @scheme[define-serializable-struct] form defines a structure type The @racket[serializable-struct] form defines a structure type
that can be @scheme[serialize]d to a value that can be printed using that can be @racket[serialize]d to a value that can be printed using
@scheme[write] and restored via @scheme[read]. The @scheme[serialize]d @racket[write] and restored via @racket[read]. The @racket[serialize]d
result can be @scheme[deserialize]d to get back an instance of the result can be @racket[deserialize]d to get back an instance of the
original structure type. The serialization form and functions are original structure type. The serialization form and functions are
provided by the @schememodname[scheme/serialize] library. provided by the @racketmodname[racket/serialize] library.
@examples[ @examples[
(require scheme/serialize) (require racket/serialize)
(define-serializable-struct posn (x y) #:transparent) (serializable-struct posn (x y) #:transparent)
(deserialize (serialize (make-posn 1 2))) (deserialize (serialize (posn 1 2)))
(write (serialize (make-posn 1 2))) (write (serialize (posn 1 2)))
(define-values (in out) (make-pipe)) (define-values (in out) (make-pipe))
(write (serialize (make-posn 1 2)) out) (write (serialize (posn 1 2)) out)
(deserialize (read in)) (deserialize (read in))
] ]
In addition to the names bound by @scheme[define-struct], In addition to the names bound by @racket[struct],
@scheme[define-serializable-struct] binds an identifier with @racket[serializable-struct] binds an identifier with deserialization
deserialization information, and it automatically @scheme[provide]s information, and it automatically @racket[provide]s the
the deserialization identifier from a module context. This deserialization identifier from a module context. This deserialization
deserialization identifier is accessed reflectively when a value is identifier is accessed reflectively when a value is deserialized.
deserialized.
@; ---------------------------------------------------------------------- @; ----------------------------------------------------------------------
@section{Bytes, Characters, and Encodings} @section[#:tag "encodings"]{Bytes, Characters, and Encodings}
Functions like @scheme[read-line], @scheme[read], @scheme[display], Functions like @racket[read-line], @racket[read], @racket[display],
and @scheme[write] all work in terms of @tech{characters} (which and @racket[write] all work in terms of @tech{characters} (which
correspond to Unicode scalar values). Conceptually, they are correspond to Unicode scalar values). Conceptually, they are
implemented in terms of @scheme[read-char] and @scheme[write-char]. implemented in terms of @racket[read-char] and @racket[write-char].
More primitively, ports read and write @tech{bytes}, instead of More primitively, ports read and write @tech{bytes}, instead of
@tech{characters}. The functions @scheme[read-byte] and @tech{characters}. The functions @racket[read-byte] and
@scheme[write-byte] read and write raw bytes. Other functions, such as @racket[write-byte] read and write raw bytes. Other functions, such as
@scheme[read-bytes-line], build on top of byte operations instead of @racket[read-bytes-line], build on top of byte operations instead of
character operations. character operations.
In fact, the @scheme[read-char] and @scheme[write-char] functions are In fact, the @racket[read-char] and @racket[write-char] functions are
conceptually implemented in terms of @scheme[read-byte] and conceptually implemented in terms of @racket[read-byte] and
@scheme[write-byte]. When a single byte's value is less than 128, then @racket[write-byte]. When a single byte's value is less than 128, then
it corresponds to an ASCII character. Any other byte is treated as it corresponds to an ASCII character. Any other byte is treated as
part of a UTF-8 sequence, where UTF-8 is a particular standard way of part of a UTF-8 sequence, where UTF-8 is a particular standard way of
encoding Unicode scalar values in bytes (which has the nice property encoding Unicode scalar values in bytes (which has the nice property
that ASCII characters are encoded as themselves). Thus, a single that ASCII characters are encoded as themselves). Thus, a single
@scheme[read-char] may call @scheme[read-byte] multiple times, and a @racket[read-char] may call @racket[read-byte] multiple times, and a
single @scheme[write-char] may generate multiple output bytes. single @racket[write-char] may generate multiple output bytes.
The @scheme[read-char] and @scheme[write-char] operations The @racket[read-char] and @racket[write-char] operations
@emph{always} use a UTF-8 encoding. If you have a text stream that @emph{always} use a UTF-8 encoding. If you have a text stream that
uses a different encoding, or if you want to generate a text stream in uses a different encoding, or if you want to generate a text stream in
a different encoding, use @scheme[reencode-input-port] or a different encoding, use @racket[reencode-input-port] or
@scheme[reencode-output-port]. The @scheme[reencode-input-port] @racket[reencode-output-port]. The @racket[reencode-input-port]
function converts an input stream from an encoding that you specify function converts an input stream from an encoding that you specify
into a UTF-8 stream; that way, @scheme[read-char] sees UTF-8 into a UTF-8 stream; that way, @racket[read-char] sees UTF-8
encodings, even though the original used a different encoding. Beware, encodings, even though the original used a different encoding. Beware,
however, that @scheme[read-byte] also sees the re-encoded data, however, that @racket[read-byte] also sees the re-encoded data,
instead of the original byte stream. instead of the original byte stream.
@; ---------------------------------------------------------------------- @; ----------------------------------------------------------------------
@section{I/O Patterns} @section[#:tag "io-patterns"]{I/O Patterns}
@(begin @(begin
(define port-eval (make-base-eval)) (define port-eval (make-base-eval))
(interaction-eval #:eval port-eval (require scheme/port))) (interaction-eval #:eval port-eval (require racket/port)))
If you want to process individual lines of a file, then you can use If you want to process individual lines of a file, then you can use
@scheme[for] with @scheme[in-lines]: @racket[for] with @racket[in-lines]:
@interaction[ @interaction[
(define (upcase-all in) (define (upcase-all in)
@ -401,8 +427,8 @@ regular expression (see @secref["regexp"]) to the stream:
(has-hello? (open-input-string "goodbye")) (has-hello? (open-input-string "goodbye"))
] ]
If you want to copy one port into another, use @scheme[copy-port] from If you want to copy one port into another, use @racket[copy-port] from
@schememodname[scheme/port], which efficiently transfers large blocks @racketmodname[racket/port], which efficiently transfers large blocks
when lots of data is available, but also transfers small blocks when lots of data is available, but also transfers small blocks
immediately if that's all that is available: immediately if that's all that is available:

View File

@ -8,14 +8,14 @@
A @deftech{macro} is a syntactic form with an associated A @deftech{macro} is a syntactic form with an associated
@deftech{transformer} that @deftech{expands} the original form @deftech{transformer} that @deftech{expands} the original form
into existing forms. To put it another way, a macro is an into existing forms. To put it another way, a macro is an
extension to the Scheme compiler. Most of the syntactic forms of extension to the Racket compiler. Most of the syntactic forms of
@schememodname[scheme/base] and @schememodname[scheme] are @racketmodname[racket/base] and @racketmodname[racket] are
actually macros that expand into a small set of core constructs. actually macros that expand into a small set of core constructs.
Like many languages, Scheme provides pattern-based macros that Like many languages, Racket provides pattern-based macros that
make simple transformations easy to implement and reliable to make simple transformations easy to implement and reliable to
use. Scheme also supports arbitrary macro transformers that are use. Racket also supports arbitrary macro transformers that are
implemented in Scheme---or in a macro-extended variant of Scheme. implemented in Racket---or in a macro-extended variant of Racket.
@local-table-of-contents[] @local-table-of-contents[]

View File

@ -2,16 +2,16 @@
@(require scribble/manual @(require scribble/manual
scribble/eval scribble/eval
"guide-utils.ss" "guide-utils.ss"
(for-label scheme/match)) (for-label racket/match))
@(begin @(begin
(define match-eval (make-base-eval)) (define match-eval (make-base-eval))
(interaction-eval #:eval match-eval (require scheme/match))) (interaction-eval #:eval match-eval (require racket/match)))
@title[#:tag "match"]{Pattern Matching} @title[#:tag "match"]{Pattern Matching}
The @scheme[match] form supports pattern matching on arbitrary Scheme The @racket[match] form supports pattern matching on arbitrary Racket
values, as opposed to functions like @scheme[regexp-match] that values, as opposed to functions like @racket[regexp-match] that
compare regular expressions to byte and character sequences (see compare regular expressions to byte and character sequences (see
@secref["regexp"]). @secref["regexp"]).
@ -20,15 +20,15 @@ compare regular expressions to byte and character sequences (see
[pattern expr ...+] ...) [pattern expr ...+] ...)
] ]
The @scheme[match] form takes the result of @scheme[target-expr] and The @racket[match] form takes the result of @racket[target-expr] and
tries to match each @scheme[_pattern] in order. As soon as it finds a tries to match each @racket[_pattern] in order. As soon as it finds a
match, it evaluates the corresponding @scheme[_expr] sequence to match, it evaluates the corresponding @racket[_expr] sequence to
obtain the result for the @scheme[match] form. If @scheme[_pattern] obtain the result for the @racket[match] form. If @racket[_pattern]
includes @deftech{pattern variables}, they are treated like wildcards, includes @deftech{pattern variables}, they are treated like wildcards,
and each variable is bound in the @scheme[_expr] to the input and each variable is bound in the @racket[_expr] to the input
fragments that it matched. fragments that it matched.
Most Scheme literal expressions can be used as patterns: Most Racket literal expressions can be used as patterns:
@interaction[ @interaction[
#:eval match-eval #:eval match-eval
@ -45,7 +45,7 @@ Most Scheme literal expressions can be used as patterns:
[#f 'boolean]) [#f 'boolean])
] ]
Constructors like @scheme[cons], @scheme[list], and @scheme[vector] Constructors like @racket[cons], @racket[list], and @racket[vector]
can be used to create patterns that match pairs, lists, and vectors: can be used to create patterns that match pairs, lists, and vectors:
@interaction[ @interaction[
@ -61,16 +61,16 @@ can be used to create patterns that match pairs, lists, and vectors:
[(vector 1 2) 'vector]) [(vector 1 2) 'vector])
] ]
The @scheme[struct] construct matches an instance of a particular A constructor bound with @scheme[struct] also can be used as a pattern
structure type: constructor:
@interaction[ @interaction[
#:eval match-eval #:eval match-eval
(define-struct shoe (size color)) (struct shoe (size color))
(define-struct hat (size style)) (struct hat (size style))
(match (make-hat 23 'bowler) (match (hat 23 'bowler)
[(struct shoe (10 'white)) "bottom"] [(shoe 10 'white) "bottom"]
[(struct hat (23 'bowler)) "top"]) [(hat 23 'bowler) "top"])
] ]
Unquoted, non-constructor identifiers in a pattern are @tech{pattern Unquoted, non-constructor identifiers in a pattern are @tech{pattern
@ -106,8 +106,8 @@ result expression to a list of matches:
[else 'other]) [else 'other])
(match '(1 2 3 4) (match '(1 2 3 4)
[(list 1 x ... 4) x]) [(list 1 x ... 4) x])
(match (list (make-hat 23 'bowler) (make-hat 22 'pork-pie)) (match (list (hat 23 'bowler) (hat 22 'pork-pie))
[(list (struct hat (sz styl)) ...) (apply + sz)]) [(list (hat sz styl) ...) (apply + sz)])
] ]
Ellipses can be nested to match nested repetitions, and in that case, Ellipses can be nested to match nested repetitions, and in that case,
@ -119,11 +119,11 @@ pattern variables can be bound to lists of lists of matches:
[(list (list '! x ...) ...) x]) [(list (list '! x ...) ...) x])
] ]
For information on many more pattern forms, see @schememodname[scheme/match]. For information on many more pattern forms, see @racketmodname[racket/match].
Forms like @scheme[match-let] and @scheme[match-lambda] support Forms like @racket[match-let] and @racket[match-lambda] support
patterns in positions that otherwise must be identifiers. For example, patterns in positions that otherwise must be identifiers. For example,
@scheme[match-let] generalizes @scheme[let] to a @as-index{destructing @racket[match-let] generalizes @racket[let] to a @as-index{destructing
bind}: bind}:
@interaction[ @interaction[
@ -132,7 +132,7 @@ bind}:
(list z y x)) (list z y x))
] ]
For information on these additional forms, see @schememodname[scheme/match]. For information on these additional forms, see @racketmodname[racket/match].
@refdetails["match"]{pattern matching} @refdetails["match"]{pattern matching}

View File

@ -1,12 +1,12 @@
#lang scribble/doc #lang scribble/doc
@(require scribble/manual @(require scribble/manual
scribble/eval scribble/eval
scheme/class racket/class
"guide-utils.ss") "guide-utils.ss")
@title[#:tag "reflection" #:style 'toc]{Reflection and Dynamic Evaluation} @title[#:tag "reflection" #:style 'toc]{Reflection and Dynamic Evaluation}
Scheme is a @italic{dynamic} language. It offers numerous facilities Racket is a @italic{dynamic} language. It offers numerous facilities
for loading, compiling, and even constructing new code at run for loading, compiling, and even constructing new code at run
time. time.
@ -14,16 +14,16 @@ time.
@; ---------------------------------------------------------------------- @; ----------------------------------------------------------------------
@section[#:tag "eval"]{@scheme[eval]} @section[#:tag "eval"]{@racket[eval]}
The @scheme[eval] function takes a ``quoted'' expression or definition The @racket[eval] function takes a ``quoted'' expression or definition
and evaluates it: and evaluates it:
@interaction[ @interaction[
(eval '(+ 1 2)) (eval '(+ 1 2))
] ]
The power of @scheme[eval] that is that an expression can be The power of @racket[eval] that is that an expression can be
constructed dynamically: constructed dynamically:
@interaction[ @interaction[
@ -36,7 +36,7 @@ constructed dynamically:
] ]
Of course, if we just wanted to evaluate expressions with given values Of course, if we just wanted to evaluate expressions with given values
for @scheme[x] and @scheme[y], we do not need @scheme[eval]. A more for @racket[x] and @racket[y], we do not need @racket[eval]. A more
direct approach is to use first-class functions: direct approach is to use first-class functions:
@interaction[ @interaction[
@ -46,25 +46,25 @@ direct approach is to use first-class functions:
(apply-formula (lambda (x y) (+ (* x y) y))) (apply-formula (lambda (x y) (+ (* x y) y)))
] ]
However, if expressions like @scheme[(+ x y)] and @scheme[(+ (* x y) However, if expressions like @racket[(+ x y)] and @racket[(+ (* x y)
y)] are read from a file supplied by a user, for example, then y)] are read from a file supplied by a user, for example, then
@scheme[eval] might be appropriate. Simialrly, the @tech{REPL} reads @racket[eval] might be appropriate. Simialrly, the @tech{REPL} reads
expressions that are typed by a user and uses @scheme[eval] to expressions that are typed by a user and uses @racket[eval] to
evaluate them. evaluate them.
Also, @scheme[eval] is often used directly or indirectly on whole Also, @racket[eval] is often used directly or indirectly on whole
modules. For example, a program might load a module on demand using modules. For example, a program might load a module on demand using
@scheme[dynamic-require], which is essentially a wrapper around @racket[dynamic-require], which is essentially a wrapper around
@scheme[eval] to dynamically load the module code. @racket[eval] to dynamically load the module code.
@; ---------------------------------------- @; ----------------------------------------
@subsection{Local Scopes} @subsection{Local Scopes}
The @scheme[eval] function cannot see local bindings in the context The @racket[eval] function cannot see local bindings in the context
where it is called. For example, calling @scheme[eval] inside an where it is called. For example, calling @racket[eval] inside an
unquoted @scheme[let] form to evaluate a formula does not make values unquoted @racket[let] form to evaluate a formula does not make values
visible for @scheme[x] and @scheme[y]: visible for @racket[x] and @racket[y]:
@interaction[ @interaction[
(define (broken-eval-formula formula) (define (broken-eval-formula formula)
@ -74,29 +74,29 @@ visible for @scheme[x] and @scheme[y]:
(broken-eval-formula '(+ x y)) (broken-eval-formula '(+ x y))
] ]
The @scheme[eval] function cannot see the @scheme[x] and @scheme[y] The @racket[eval] function cannot see the @racket[x] and @racket[y]
bindings precisely because it is a function, and Scheme is a lexically bindings precisely because it is a function, and Racket is a lexically
scoped language. Imagine if @scheme[eval] were implemented as scoped language. Imagine if @racket[eval] were implemented as
@schemeblock[ @racketblock[
(define (eval x) (define (eval x)
(eval-expanded (macro-expand x))) (eval-expanded (macro-expand x)))
] ]
then at the point when @scheme[eval-expanded] is called, the most then at the point when @racket[eval-expanded] is called, the most
recent binding of @scheme[x] is to the expression to evaluate, not the recent binding of @racket[x] is to the expression to evaluate, not the
@scheme[let] binding in @scheme[broken-eval-formula]. Lexical scope @racket[let] binding in @racket[broken-eval-formula]. Lexical scope
prevents such confusing and fragile behavior, and consequently prevents such confusing and fragile behavior, and consequently
prevents @scheme[eval] from seeing local bindings in the context where prevents @racket[eval] from seeing local bindings in the context where
it is called. it is called.
You might imagine that even though @scheme[eval] cannot see the local You might imagine that even though @racket[eval] cannot see the local
bindings in @scheme[broken-eval-formula], there must actually be a bindings in @racket[broken-eval-formula], there must actually be a
data structure mapping @scheme[x] to @scheme[2] and @scheme[y] to data structure mapping @racket[x] to @racket[2] and @racket[y] to
@scheme[3], and you would like a way to get that data structure. In @racket[3], and you would like a way to get that data structure. In
fact, no such data structure exists; the compiler is free to replace fact, no such data structure exists; the compiler is free to replace
every use of @scheme[x] with @scheme[2] at compile time, so that the every use of @racket[x] with @racket[2] at compile time, so that the
local binding of @scheme[x] does not exist in any concrete sense at local binding of @racket[x] does not exist in any concrete sense at
run-time. Even when variables cannot be eliminated by run-time. Even when variables cannot be eliminated by
constant-folding, normally the names of the variables can be constant-folding, normally the names of the variables can be
eliminated, and the data structures that hold local values do not eliminated, and the data structures that hold local values do not
@ -106,26 +106,29 @@ resemble a mapping from names to values.
@subsection[#:tag "namespaces"]{Namespaces} @subsection[#:tag "namespaces"]{Namespaces}
Since @scheme[eval] cannot see the bindings from the context where it Since @racket[eval] cannot see the bindings from the context where it
is called, another mechanism is needed to determine dynamically is called, another mechanism is needed to determine dynamically
available bindings. A @deftech{namespace} is a first-class value that available bindings. A @deftech{namespace} is a first-class value that
encapsulates the bindings available for dynamic evaluation. encapsulates the bindings available for dynamic evaluation.
@margin-note{Informally, the term @defterm{namespace} is sometimes @margin-note{Informally, the term @defterm{namespace} is sometimes
used interchangeably with @defterm{environment} or used interchangeably with @defterm{environment} or
@defterm{scope}. In PLT Scheme, the term @defterm{namespace} has the @defterm{scope}. In Racket, the term @defterm{namespace} has the
more specific, dynamic meaning given above, and it should not be more specific, dynamic meaning given above, and it should not be
confused with static lexical concepts.} confused with static lexical concepts.}
Some functions, such as @scheme[eval], accept an optional namespace Some functions, such as @racket[eval], accept an optional namespace
argument. More often, the namespace used by a dynamic operation is the argument. More often, the namespace used by a dynamic operation is the
@deftech{current namespace} as determined by the @deftech{current namespace} as determined by the
@scheme[current-namespace] parameter. @racket[current-namespace] @tech{parameter}.
When @scheme[eval] is used in a @tech{REPL}, the current is the one @margin-note{See @secref["parameterize"] for an introduction to
parameters.}
When @racket[eval] is used in a @tech{REPL}, the current is the one
that the @tech{REPL} uses for evaluating expressions. That's why the that the @tech{REPL} uses for evaluating expressions. That's why the
following interaction successfully accesses @scheme[x] via following interaction successfully accesses @racket[x] via
@scheme[eval]: @racket[eval]:
@interaction[ @interaction[
(define x 3) (define x 3)
@ -133,34 +136,34 @@ following interaction successfully accesses @scheme[x] via
] ]
In contrast, try the following a simple module and running in directly In contrast, try the following a simple module and running in directly
in DrScheme's @onscreen{Module} language or supplying the file as a in DrRacket or supplying the file as a command-line argument to
command-line argument to @exec{mzscheme}: @exec{racket}:
@schememod[ @racketmod[
scheme racket
(eval '(cons 1 2)) (eval '(cons 1 2))
] ]
This fails because the initial current namespace is empty. When you This fails because the initial current namespace is empty. When you
run @exec{mzscheme} in interactive mode (see run @exec{racket} in interactive mode (see
@secref["start-interactive-mode"]), the initial namespace is @secref["start-interactive-mode"]), the initial namespace is
initialized with the exports of the @scheme[scheme] module, but when initialized with the exports of the @racket[racket] module, but when
you run a module directly, the initial namespace starts empty. you run a module directly, the initial namespace starts empty.
In general, it's a bad idea to use @scheme[eval] with whatever In general, it's a bad idea to use @racket[eval] with whatever
namespace happens to be installed. Instead, create a namespace namespace happens to be installed. Instead, create a namespace
explicitly and install it for the call to eval: explicitly and install it for the call to eval:
@schememod[ @racketmod[
scheme racket
(define ns (make-base-namespace)) (define ns (make-base-namespace))
(eval '(cons 1 2) ns) (code:comment @#,t{works}) (eval '(cons 1 2) ns) (code:comment @#,t{works})
] ]
The @scheme[make-base-namespace] function creates a namespace that is The @racket[make-base-namespace] function creates a namespace that is
initialized with the exports of @scheme[scheme/base]. The later initialized with the exports of @racket[racket/base]. The later
section @secref["mk-namespace"] provides more information on creating section @secref["mk-namespace"] provides more information on creating
and configuring namespaces. and configuring namespaces.
@ -168,40 +171,40 @@ and configuring namespaces.
@subsection{Namespaces and Modules} @subsection{Namespaces and Modules}
As with @scheme[let] bindings, lexical scope means that @scheme[eval] As with @racket[let] bindings, lexical scope means that @racket[eval]
cannot automatically see the definitions of a @scheme[module] in which cannot automatically see the definitions of a @racket[module] in which
it is called. Unlike @scheme[let] bindings, however, Scheme provides a it is called. Unlike @racket[let] bindings, however, Racket provides a
way to reflect a module into a @tech{namespace}. way to reflect a module into a @tech{namespace}.
The @scheme[module->namespace] function takes a quoted @tech{module The @racket[module->namespace] function takes a quoted @tech{module
path} and produces a namespace for evaluating expressions and path} and produces a namespace for evaluating expressions and
definitions as if they appears in the @scheme[module] body: definitions as if they appears in the @racket[module] body:
@interaction[ @interaction[
(module m scheme/base (module m racket/base
(define x 11)) (define x 11))
(require 'm) (require 'm)
(define ns (module->namespace ''m)) (define ns (module->namespace ''m))
(eval 'x ns) (eval 'x ns)
] ]
@margin-note{The double quoting in @scheme[''m] is because @scheme['m] @margin-note{The double quoting in @racket[''m] is because @racket['m]
is a module path that refers to an interactively declared module, and is a module path that refers to an interactively declared module, and
so @scheme[''m] is the quoted form of the path.} so @racket[''m] is the quoted form of the path.}
The @scheme[module->namespace] function is mostly useful from outside The @racket[module->namespace] function is mostly useful from outside
a module, where the module's full name is known. Inside a a module, where the module's full name is known. Inside a
@scheme[module] form, however, the full name of a module may not be @racket[module] form, however, the full name of a module may not be
known, because it may depend on where the module source is location known, because it may depend on where the module source is location
when it is eventually loaded. when it is eventually loaded.
From within a @scheme[module], use @scheme[define-namespace-anchor] to From within a @racket[module], use @racket[define-namespace-anchor] to
declare a reflection hook on the module, and use declare a reflection hook on the module, and use
@scheme[namespace-anchor->namespace] to reel in the module's @racket[namespace-anchor->namespace] to reel in the module's
namespace: namespace:
@schememod[ @racketmod[
scheme racket
(define-namespace-anchor a) (define-namespace-anchor a)
(define ns (namespace-anchor->namespace a)) (define ns (namespace-anchor->namespace a))
@ -209,7 +212,7 @@ scheme
(define x 1) (define x 1)
(define y 2) (define y 2)
(eval '(cons x y) ns) (code:comment @#,t{produces @schemeresult[(1 . 2)]}) (eval '(cons x y) ns) (code:comment @#,t{produces @racketresult[(1 . 2)]})
] ]
@ -222,8 +225,8 @@ A @tech{namespace} encapsulates two pieces of information:
@itemize[ @itemize[
@item{A mapping from identifiers to bindings. For example, a @item{A mapping from identifiers to bindings. For example, a
namespace might map the identifier @schemeidfont{lambda} to the namespace might map the identifier @racketidfont{lambda} to the
@scheme[lambda] form. An ``empty'' namespace is one that maps @racket[lambda] form. An ``empty'' namespace is one that maps
every identifier to an uninitialized top-level variable.} every identifier to an uninitialized top-level variable.}
@item{A mapping from module names to module declarations and @item{A mapping from module names to module declarations and
@ -232,39 +235,39 @@ A @tech{namespace} encapsulates two pieces of information:
] ]
The first mapping is used for evaluating expressions in a top-level The first mapping is used for evaluating expressions in a top-level
context, as in @scheme[(eval '(lambda (x) (+ x 1)))]. The second context, as in @racket[(eval '(lambda (x) (+ x 1)))]. The second
mapping is used, for example, by @scheme[dynamic-require] to locate a mapping is used, for example, by @racket[dynamic-require] to locate a
module. The call @scheme[(eval '(require scheme/base))] normally uses module. The call @racket[(eval '(require racket/base))] normally uses
both pieces: the identifier mapping determines the binding of both pieces: the identifier mapping determines the binding of
@schemeidfont{require}; if it turns out to mean @scheme[require], then @racketidfont{require}; if it turns out to mean @racket[require], then
the module mapping is used to locate the @schememodname[scheme/base] the module mapping is used to locate the @racketmodname[racket/base]
module. module.
From the perspective of the core Scheme run-time system, all From the perspective of the core Racket run-time system, all
evaluation is reflective. Execution starts with an initial namespace evaluation is reflective. Execution starts with an initial namespace
that contains a few primitive modules, and that is further populated that contains a few primitive modules, and that is further populated
by loading files and modules as specified on the command line or as by loading files and modules as specified on the command line or as
supplied in the @tech{REPL}. Top-level @scheme[require] and supplied in the @tech{REPL}. Top-level @racket[require] and
@scheme[define] forms adjusts the identifier mapping, and module @racket[define] forms adjusts the identifier mapping, and module
declarations (typically loaded on demand for a @scheme[require] form) declarations (typically loaded on demand for a @racket[require] form)
adjust the module mapping. adjust the module mapping.
@; ---------------------------------------- @; ----------------------------------------
@subsection{Creating and Installing Namespaces} @subsection{Creating and Installing Namespaces}
The function @scheme[make-empty-namespace] creates a new, empty The function @racket[make-empty-namespace] creates a new, empty
@tech{namespace}. Since the namespace is truly empty, it cannot at @tech{namespace}. Since the namespace is truly empty, it cannot at
first be used to evaluate any top-level expression---not even first be used to evaluate any top-level expression---not even
@scheme[(require scheme)]. In particular, @racket[(require racket)]. In particular,
@schemeblock[ @racketblock[
(parameterize ([current-namespace (make-empty-namespace)]) (parameterize ([current-namespace (make-empty-namespace)])
(namespace-require 'scheme)) (namespace-require 'racket))
] ]
fails, because the namespace does not include the primitive modules on fails, because the namespace does not include the primitive modules on
which @scheme[scheme] is built. which @racket[racket] is built.
To make a namespace useful, some modules much be @deftech{attached} To make a namespace useful, some modules much be @deftech{attached}
from an existing namespace. Attaching a module adjusts the mapping of from an existing namespace. Attaching a module adjusts the mapping of
@ -272,47 +275,47 @@ module names to instances by transitively copying entries (the module
and all its imports) from an existing namespace's mapping. Normally, and all its imports) from an existing namespace's mapping. Normally,
instead of just attaching the primitive modules---whose names and instead of just attaching the primitive modules---whose names and
organization are subject to change---a higher-level module is organization are subject to change---a higher-level module is
attached, such as @schememodname[scheme] or attached, such as @racketmodname[racket] or
@schememodname[scheme/base]. @racketmodname[racket/base].
The @scheme[make-base-empty-namespace] function provides a namespace The @racket[make-base-empty-namespace] function provides a namespace
that is empty, except that @schememodname[scheme/base] is that is empty, except that @racketmodname[racket/base] is
attached. The resulting namespace is still ``empty'' in the sense that attached. The resulting namespace is still ``empty'' in the sense that
the identifiers-to-bindings part of the namespace has no mappings; the identifiers-to-bindings part of the namespace has no mappings;
only the module mapping has been populated. Nevertheless, with an only the module mapping has been populated. Nevertheless, with an
initial module mapping, further modules can be loaded. initial module mapping, further modules can be loaded.
A namespace created with @scheme[make-base-empty-namespace] is A namespace created with @racket[make-base-empty-namespace] is
suitable for many basic dynamic tasks. For example, suppose that a suitable for many basic dynamic tasks. For example, suppose that a
@schememodfont{my-dsl} library implements a domain-specific language @racketmodfont{my-dsl} library implements a domain-specific language
in which you want to execute commands from a user-specified file. A in which you want to execute commands from a user-specified file. A
namespace created with @scheme[make-base-empty-namespace] is enough to namespace created with @racket[make-base-empty-namespace] is enough to
get started: get started:
@schemeblock[ @racketblock[
(define (run-dsl file) (define (run-dsl file)
(parameterize ([current-namespace (make-base-empty-namespace)]) (parameterize ([current-namespace (make-base-empty-namespace)])
(namespace-require 'my-dsl) (namespace-require 'my-dsl)
(load file))) (load file)))
] ]
Note that the @scheme[parameterize] of @scheme[current-namespace] does Note that the @racket[parameterize] of @racket[current-namespace] does
not affect the meaning of identifiers like @scheme[namespace-require] not affect the meaning of identifiers like @racket[namespace-require]
within the @scheme[parameterize] body. Those identifiers obtain their within the @racket[parameterize] body. Those identifiers obtain their
meaning from the enclosing context (probably a module). Only meaning from the enclosing context (probably a module). Only
expressions that are dynamic with respect to this code, such as the expressions that are dynamic with respect to this code, such as the
content of @scheme[load]ed files, are affected by the content of @racket[load]ed files, are affected by the
@scheme[parameterize]. @racket[parameterize].
Another subtle point in the above example is the use of Another subtle point in the above example is the use of
@scheme[(namespace-require 'my-dsl)] instead of @scheme[(eval @racket[(namespace-require 'my-dsl)] instead of @racket[(eval
'(require my-dsl))]. The latter would not work, because @scheme[eval] '(require my-dsl))]. The latter would not work, because @racket[eval]
needs to obtain a meaning for @scheme[require] in the namespace, and needs to obtain a meaning for @racket[require] in the namespace, and
the namespace's identifier mapping is initially empty. The the namespace's identifier mapping is initially empty. The
@scheme[namespace-require] function, in contrast, directly imports the @racket[namespace-require] function, in contrast, directly imports the
given module into the current namespace. Starting with given module into the current namespace. Starting with
@scheme[(namespace-require 'scheme/base)] would introduce a binding @racket[(namespace-require 'racket/base)] would introduce a binding
for @schemeidfont{require} and make a subsequent @scheme[(eval for @racketidfont{require} and make a subsequent @racket[(eval
'(require my-dsl))] work. The above is better, not only because it is '(require my-dsl))] work. The above is better, not only because it is
more compact, but also because it avoids introducing bindings that are more compact, but also because it avoids introducing bindings that are
not part of the domain-specific languages. not part of the domain-specific languages.
@ -323,88 +326,88 @@ not part of the domain-specific languages.
Modules not attached to a new namespace will be loaded and Modules not attached to a new namespace will be loaded and
instantiated afresh if they are demanded by evaluation. For example, instantiated afresh if they are demanded by evaluation. For example,
@schememodname[scheme/base] does not include @racketmodname[racket/base] does not include
@schememodname[scheme/class], and loading @schememodname[scheme/class] @racketmodname[racket/class], and loading @racketmodname[racket/class]
again will create a distinct class datatype: again will create a distinct class datatype:
@interaction[ @interaction[
(require scheme/class) (require racket/class)
(class? object%) (class? object%)
(class? (class?
(parameterize ([current-namespace (make-base-empty-namespace)]) (parameterize ([current-namespace (make-base-empty-namespace)])
(namespace-require 'scheme/class) (code:comment @#,t{loads again}) (namespace-require 'racket/class) (code:comment @#,t{loads again})
(eval 'object%))) (eval 'object%)))
] ]
For cases when dynamically loaded code needs to share more code and For cases when dynamically loaded code needs to share more code and
data with its context, use the @scheme[namespace-attach-module] data with its context, use the @racket[namespace-attach-module]
function. The first argument to @scheme[namespace-attach-module] is a function. The first argument to @racket[namespace-attach-module] is a
source namespace from which to draw a module instance; in some cases, source namespace from which to draw a module instance; in some cases,
the current namespace is known to include the module that needs to be the current namespace is known to include the module that needs to be
shared: shared:
@interaction[ @interaction[
(require scheme/class) (require racket/class)
(class? (class?
(let ([ns (make-base-empty-namespace)]) (let ([ns (make-base-empty-namespace)])
(namespace-attach-module (current-namespace) (namespace-attach-module (current-namespace)
'scheme/class 'racket/class
ns) ns)
(parameterize ([current-namespace ns]) (parameterize ([current-namespace ns])
(namespace-require 'scheme/class) (code:comment @#,t{uses attached}) (namespace-require 'racket/class) (code:comment @#,t{uses attached})
(eval 'object%)))) (eval 'object%))))
] ]
Within a module, however, the combination of Within a module, however, the combination of
@scheme[define-namespace-anchor] and @racket[define-namespace-anchor] and
@scheme[namespace-anchor->empty-namespace] offers a more reliable @racket[namespace-anchor->empty-namespace] offers a more reliable
method for obtaining a source namespace: method for obtaining a source namespace:
@schememod[ @racketmod[
scheme/base racket/base
(require scheme/class) (require racket/class)
(define-namespace-anchor a) (define-namespace-anchor a)
(define (load-plug-in file) (define (load-plug-in file)
(let ([ns (make-base-empty-namespace)]) (let ([ns (make-base-empty-namespace)])
(namespace-attach-module (namespace-anchor->empty-namespace a) (namespace-attach-module (namespace-anchor->empty-namespace a)
'scheme/class 'racket/class
ns) ns)
(parameterize ([current-namespace ns]) (parameterize ([current-namespace ns])
(dynamic-require file 'plug-in%)))) (dynamic-require file 'plug-in%))))
] ]
The anchor bound by @scheme[namespace-attach-module] connects the The anchor bound by @racket[namespace-attach-module] connects the
run time of a module with the namespace in which a module is loaded run time of a module with the namespace in which a module is loaded
(which might differ from the current namespace). In the above (which might differ from the current namespace). In the above
example, since the enclosing module requires example, since the enclosing module requires
@schememodname[scheme/class], the namespace produced by @racketmodname[racket/class], the namespace produced by
@scheme[namespace-anchor->empty-namespace] certainly contains an @racket[namespace-anchor->empty-namespace] certainly contains an
instance of @schememodname[scheme/class]. Moreover, that instance is instance of @racketmodname[racket/class]. Moreover, that instance is
the same as the one imported into the module, so the class datatype is the same as the one imported into the module, so the class datatype is
shared. shared.
@; ---------------------------------------------------------------------- @; ----------------------------------------------------------------------
@section[#:tag "load"]{Scripting Evaluation and Using @scheme[load]} @section[#:tag "load"]{Scripting Evaluation and Using @racket[load]}
Historically, Scheme and Lisp systems did not offer module Historically, Lisp implementations did not offer module
systems. Instead, large programs were built by essentially scripting systems. Instead, large programs were built by essentially scripting
the @tech{REPL} to evaluate program fragments in a particular order. the @tech{REPL} to evaluate program fragments in a particular order.
While @tech{REPL} scripting turns out to be a bad way to structure While @tech{REPL} scripting turns out to be a bad way to structure
programs and libraries, it is still sometimes a useful capability. programs and libraries, it is still sometimes a useful capability.
@margin-note{Describing a program via @scheme[load] interacts @margin-note{Describing a program via @racket[load] interacts
especially badly with macro-defined language extensions especially badly with macro-defined language extensions
@cite["Flatt02"].} @cite["Flatt02"].}
The @scheme[load] function runs a @tech{REPL} script by The @racket[load] function runs a @tech{REPL} script by
@scheme[read]ing S-expressions from a file, one by one, and passing @racket[read]ing S-expressions from a file, one by one, and passing
them to @scheme[eval]. If a file @filepath{place.scm} contains them to @racket[eval]. If a file @filepath{place.rkts} contains
@schemeblock[ @racketblock[
(define city "Salt Lake City") (define city "Salt Lake City")
(define state "Utah") (define state "Utah")
(printf "~a, ~a\n" city state) (printf "~a, ~a\n" city state)
@ -413,86 +416,86 @@ them to @scheme[eval]. If a file @filepath{place.scm} contains
then it can be loaded in a @tech{REPL}: then it can be loaded in a @tech{REPL}:
@interaction[ @interaction[
(eval:alts (load "place.scm") (begin (define city "Salt Lake City") (eval:alts (load "place.rkts") (begin (define city "Salt Lake City")
(printf "~a, Utah\n" city))) (printf "~a, Utah\n" city)))
city city
] ]
Since @scheme[load] uses @scheme[eval], however, a module like the Since @racket[load] uses @racket[eval], however, a module like the
following generally will not work---for the same reasons described in following generally will not work---for the same reasons described in
@secref["namespaces"]: @secref["namespaces"]:
@schememod[ @racketmod[
scheme racket
(define there "Utopia") (define there "Utopia")
(load "here.scm") (load "here.rkts")
] ]
The current namespace for evaluating the content of The current namespace for evaluating the content of
@filepath{here.scm} is likely to be empty; in any case, you cannot get @filepath{here.rkts} is likely to be empty; in any case, you cannot get
@scheme[there] from @filepath{here.scm}. Also, any definitions in @racket[there] from @filepath{here.rkts}. Also, any definitions in
@filepath{here.scm} will not become visible for use within the module; @filepath{here.rkts} will not become visible for use within the module;
after all, the @scheme[load] happens dynamically, while references to after all, the @racket[load] happens dynamically, while references to
identifiers within the module are resolved lexically, and therefore identifiers within the module are resolved lexically, and therefore
statically. statically.
Unlike @scheme[eval], @scheme[load] does not accept a namespace Unlike @racket[eval], @racket[load] does not accept a namespace
argument. To supply a namespace to @scheme[load], set the argument. To supply a namespace to @racket[load], set the
@scheme[current-namespace] parameter. The following example evaluates @racket[current-namespace] @tech{parameter}. The following example evaluates
the expressions in @filepath{here.scm} using the bindings of the the expressions in @filepath{here.rkts} using the bindings of the
@schememodname[scheme/base] module: @racketmodname[racket/base] module:
@schememod[ @racketmod[
scheme racket
(parameterize ([current-namespace (make-base-namespace)]) (parameterize ([current-namespace (make-base-namespace)])
(load "here.scm")) (load "here.rkts"))
] ]
You can even use @scheme[namespace-anchor->namespace] to make the You can even use @racket[namespace-anchor->namespace] to make the
bindings of the enclosing module accessible for dynamic evaluation. In bindings of the enclosing module accessible for dynamic evaluation. In
the following example, when @filepath{here.scm} is @scheme[load]ed, it the following example, when @filepath{here.rkts} is @racket[load]ed, it
can refer to @scheme[there] as well as the bindings of can refer to @racket[there] as well as the bindings of
@schememodname[scheme]: @racketmodname[racket]:
@schememod[ @racketmod[
scheme racket
(define there "Utopia") (define there "Utopia")
(define-namespace-anchor a) (define-namespace-anchor a)
(parameterize ([current-namespace (namespace-anchor->namespace a)]) (parameterize ([current-namespace (namespace-anchor->namespace a)])
(load "here.scm")) (load "here.rkts"))
] ]
Still, if @filepath{here.scm} defines any identifiers, the definitions Still, if @filepath{here.rkts} defines any identifiers, the definitions
cannot be directly (i.e., statically) referenced by in the enclosing cannot be directly (i.e., statically) referenced by in the enclosing
module. module.
The @schememodname[scheme/load] module language is different from The @racketmodname[racket/load] module language is different from
@schememodname[scheme] or @schememodname[scheme/base]. A module using @racketmodname[racket] or @racketmodname[racket/base]. A module using
@schememodname[scheme/load] treats all of its content as dynamic, @racketmodname[racket/load] treats all of its content as dynamic,
passing each form in the module body to @scheme[eval] (using a passing each form in the module body to @racket[eval] (using a
namespace that is initialized with @schememodname[scheme]). As a namespace that is initialized with @racketmodname[racket]). As a
result, uses of @scheme[eval] and @scheme[load] in the module body see result, uses of @racket[eval] and @racket[load] in the module body see
the same dynamic namespace as immediate body forms. For example, if the same dynamic namespace as immediate body forms. For example, if
@filepath{here.scm} contains @filepath{here.rkts} contains
@schemeblock[ @racketblock[
(define here "Morporkia") (define here "Morporkia")
(define (go!) (set! here there)) (define (go!) (set! here there))
] ]
then running then running
@schememod[ @racketmod[
scheme/load racket/load
(define there "Utopia") (define there "Utopia")
(load "here.scm") (load "here.rkts")
(go!) (go!)
(printf "~a\n" here) (printf "~a\n" here)
@ -500,12 +503,12 @@ scheme/load
prints ``Utopia''. prints ``Utopia''.
Drawbacks of using @schememodname[scheme/load] include reduced Drawbacks of using @racketmodname[racket/load] include reduced
error checking, tool support, and performance. For example, with the error checking, tool support, and performance. For example, with the
program program
@schememod[ @racketmod[
scheme/load racket/load
(define good 5) (define good 5)
(printf "running\n") (printf "running\n")
@ -513,7 +516,7 @@ good
bad bad
] ]
DrScheme's @onscreen{Check Syntax} tool cannot tell that the second DrRacket's @onscreen{Check Syntax} tool cannot tell that the second
@scheme[good] is a reference to the first, and the unbound reference @racket[good] is a reference to the first, and the unbound reference
to @scheme[bad] is reported only at run time instead of rejected to @racket[bad] is reported only at run time instead of rejected
syntactically. syntactically.

View File

@ -4,22 +4,22 @@
@title{More Libraries} @title{More Libraries}
@other-manual['(lib "scribblings/gui/gui.scrbl")] describes the PLT @other-manual['(lib "scribblings/gui/gui.scrbl")] describes the Racket
Scheme graphics toolbox, whose core is implemented by the @exec{mred} graphics toolbox, whose core is implemented by the @exec{gracket}
executable. executable.
@other-manual['(lib "scribblings/foreign/foreign.scrbl")] describes @other-manual['(lib "scribblings/foreign/foreign.scrbl")] describes
tools for using Scheme to access libraries that are normally used by C tools for using Racket to access libraries that are normally used by C
programs. programs.
@other-manual['(lib "web-server/scribblings/web-server.scrbl")] @other-manual['(lib "web-server/scribblings/web-server.scrbl")]
describes the PLT Scheme web server, which supports servlets describes the Racket web server, which supports servlets implemented
implemented in Scheme. in Racket.
@link["../index.html"]{PLT Scheme Documentation} lists documentation @link["../index.html"]{Racket Documentation} lists documentation for
for many other installed libraries. Run @exec{plt-help} to find many other installed libraries. Run @exec{raco docs} to find
documentation for libraries that are installed on your system and documentation for libraries that are installed on your system and
specific to your user account. specific to your user account.
@link["http://planet.plt-scheme.org/"]{@|PLaneT|} offers even more @link["http://planet.plt-racket.org/"]{@|PLaneT|} offers even more
downloadable packages contributed by PLT Scheme users. downloadable packages contributed by Racketeers.

View File

@ -11,52 +11,52 @@ match parts of the pattern.
@; ---------------------------------------- @; ----------------------------------------
@section{@scheme[define-syntax-rule]} @section{@racket[define-syntax-rule]}
The simplest way to create a macro is to use The simplest way to create a macro is to use
@scheme[define-syntax-rule]: @racket[define-syntax-rule]:
@specform[(define-syntax-rule pattern template)] @specform[(define-syntax-rule pattern template)]
As a running example, consider the @scheme[swap] macro, which swaps As a running example, consider the @racket[swap] macro, which swaps
the values stored in two variables. It can be implemented using the values stored in two variables. It can be implemented using
@scheme[define-syntax-rule] as follows: @racket[define-syntax-rule] as follows:
@margin-note{The macro is ``un-Schemely'' in the sense that it @margin-note{The macro is ``un-Rackety'' in the sense that it
involves side effects on variables---but the point of macros is to let involves side effects on variables---but the point of macros is to let
you add syntactic forms that some other language designer might not you add syntactic forms that some other language designer might not
approve.} approve.}
@schemeblock[ @racketblock[
(define-syntax-rule (swap x y) (define-syntax-rule (swap x y)
(let ([tmp x]) (let ([tmp x])
(set! x y) (set! x y)
(set! y tmp))) (set! y tmp)))
] ]
The @scheme[define-syntax-rule] form binds a macro that matches a The @racket[define-syntax-rule] form binds a macro that matches a
single pattern. The pattern must always start with an open parenthesis single pattern. The pattern must always start with an open parenthesis
followed by an identifier, which is @scheme[swap] in this case. After followed by an identifier, which is @racket[swap] in this case. After
the initial identifier, other identifiers are @deftech{macro pattern the initial identifier, other identifiers are @deftech{macro pattern
variables} that can match anything in a use of the macro. Thus, this variables} that can match anything in a use of the macro. Thus, this
macro matches the for @scheme[(swap _form_1 _form_2)] for any macro matches the form @racket[(swap _form1 _form2)] for any
@scheme[_form_1] and @scheme[_form_2]. @racket[_form_1] and @racket[_form_2].
@margin-note{Macro pattern variables similar to pattern variables for @margin-note{Macro pattern variables similar to pattern variables for
@scheme[match]. See @secref["match"].} @racket[match]. See @secref["match"].}
After the pattern in @scheme[define-syntax-rule] is the After the pattern in @racket[define-syntax-rule] is the
@deftech{template}. The template is used in place of a form that @deftech{template}. The template is used in place of a form that
matches the pattern, except that each instance of a pattern variable matches the pattern, except that each instance of a pattern variable
in the template is replaced with the part of the macro use the pattern in the template is replaced with the part of the macro use the pattern
variable matched. For example, in variable matched. For example, in
@schemeblock[(swap first last)] @racketblock[(swap first last)]
the pattern variable @scheme[x] matches @scheme[first] and @scheme[y] the pattern variable @racket[x] matches @racket[first] and @racket[y]
matches @scheme[last], so that the expansion is matches @racket[last], so that the expansion is
@schemeblock[ @racketblock[
(let ([tmp first]) (let ([tmp first])
(set! first last) (set! first last)
(set! last tmp)) (set! last tmp))
@ -66,20 +66,20 @@ matches @scheme[last], so that the expansion is
@section{Lexical Scope} @section{Lexical Scope}
Suppose that we use the @scheme[swap] macro to swap variables named Suppose that we use the @racket[swap] macro to swap variables named
@scheme[tmp] and @scheme[other]: @racket[tmp] and @racket[other]:
@schemeblock[ @racketblock[
(let ([tmp 5] (let ([tmp 5]
[other 6]) [other 6])
(swap tmp other) (swap tmp other)
(list tmp other)) (list tmp other))
] ]
The result of the above expression should be @schemeresult[(6 5)]. The The result of the above expression should be @racketresult[(6 5)]. The
naive expansion of this use of @scheme[swap], however, is naive expansion of this use of @racket[swap], however, is
@schemeblock[ @racketblock[
(let ([tmp 5] (let ([tmp 5]
[other 6]) [other 6])
(let ([tmp tmp]) (let ([tmp tmp])
@ -88,14 +88,14 @@ naive expansion of this use of @scheme[swap], however, is
(list tmp other)) (list tmp other))
] ]
whose result is @schemeresult[(5 6)]. The problem is that the naive whose result is @racketresult[(5 6)]. The problem is that the naive
expansion confuses the @scheme[tmp] in the context where @scheme[swap] expansion confuses the @racket[tmp] in the context where @racket[swap]
is used with the @scheme[tmp] that is in the macro template. is used with the @racket[tmp] that is in the macro template.
Scheme doesn't produce the naive expansion for the above use of Racket doesn't produce the naive expansion for the above use of
@scheme[swap]. Instead, it produces @racket[swap]. Instead, it produces
@schemeblock[ @racketblock[
(let ([tmp 5] (let ([tmp 5]
[other 6]) [other 6])
(let ([tmp_1 tmp]) (let ([tmp_1 tmp])
@ -104,10 +104,10 @@ Scheme doesn't produce the naive expansion for the above use of
(list tmp other)) (list tmp other))
] ]
with the correct result in @schemeresult[(6 5)]. Similarly, in the with the correct result in @racketresult[(6 5)]. Similarly, in the
example example
@schemeblock[ @racketblock[
(let ([set! 5] (let ([set! 5]
[other 6]) [other 6])
(swap set! other) (swap set! other)
@ -116,7 +116,7 @@ example
the expansion is the expansion is
@schemeblock[ @racketblock[
(let ([set!_1 5] (let ([set!_1 5]
[other 6]) [other 6])
(let ([tmp_1 tmp]) (let ([tmp_1 tmp])
@ -125,23 +125,23 @@ the expansion is
(list set!_1 other)) (list set!_1 other))
] ]
so that the local @scheme[set!] binding doesn't interfere with the so that the local @racket[set!] binding doesn't interfere with the
assignments introduced by the macro template. assignments introduced by the macro template.
In other words, Scheme's pattern-based macros automatically maintain In other words, Racket's pattern-based macros automatically maintain
lexical scope, so macro implementors can reason about variable lexical scope, so macro implementors can reason about variable
reference in macros and macro uses in the same way as for functions reference in macros and macro uses in the same way as for functions
and function calls. and function calls.
@; ---------------------------------------- @; ----------------------------------------
@section{@scheme[define-syntax] and @scheme[syntax-rules]} @section{@racket[define-syntax] and @racket[syntax-rules]}
The @scheme[define-syntax-rule] form binds a macro that matches a The @racket[define-syntax-rule] form binds a macro that matches a
single pattern, but Scheme's macro system supports transformers that single pattern, but Racket's macro system supports transformers that
match multiple patterns starting with the same identifier. To write match multiple patterns starting with the same identifier. To write
such macros, the programmer much use the more general such macros, the programmer much use the more general
@scheme[define-syntax] form along with the @scheme[syntax-rules] @racket[define-syntax] form along with the @racket[syntax-rules]
transformer form: transformer form:
@specform[#:literals (syntax-rules) @specform[#:literals (syntax-rules)
@ -150,25 +150,25 @@ transformer form:
[pattern template] [pattern template]
...))] ...))]
@margin-note{The @scheme[define-syntax-rule] form is itself a macro @margin-note{The @racket[define-syntax-rule] form is itself a macro
that expands into @scheme[define-syntax] with a @scheme[syntax-rules] that expands into @racket[define-syntax] with a @racket[syntax-rules]
form that contains only one pattern and template.} form that contains only one pattern and template.}
For example, suppose we would like a @scheme[rotate] macro that For example, suppose we would like a @racket[rotate] macro that
generalizes @scheme[swap] to work on either two or three identifiers, generalizes @racket[swap] to work on either two or three identifiers,
so that so that
@schemeblock[ @racketblock[
(let ([red 1] [green 2] [blue 3]) (let ([red 1] [green 2] [blue 3])
(rotate red green) (code:comment @#,t{swaps}) (rotate red green) (code:comment @#,t{swaps})
(rotate red green blue) (code:comment @#,t{rotates left}) (rotate red green blue) (code:comment @#,t{rotates left})
(list red green blue)) (list red green blue))
] ]
produces @schemeresult[(1 3 2)]. We can implement @scheme[rotate] produces @racketresult[(1 3 2)]. We can implement @racket[rotate]
using @scheme[syntax-rules]: using @racket[syntax-rules]:
@schemeblock[ @racketblock[
(define-syntax rotate (define-syntax rotate
(syntax-rules () (syntax-rules ()
[(rotate a b) (swap a b)] [(rotate a b) (swap a b)]
@ -177,27 +177,27 @@ using @scheme[syntax-rules]:
(swap b c))])) (swap b c))]))
] ]
The expression @scheme[(rotate red green)] matches the first pattern The expression @racket[(rotate red green)] matches the first pattern
in the @scheme[syntax-rules] form, so it expands to @scheme[(swap red in the @racket[syntax-rules] form, so it expands to @racket[(swap red
green)]. The expression @scheme[(rotate a b c)] matches the second green)]. The expression @racket[(rotate a b c)] matches the second
pattern, so it expands to @scheme[(begin (swap red green) (swap green pattern, so it expands to @racket[(begin (swap red green) (swap green
blue))]. blue))].
@; ---------------------------------------- @; ----------------------------------------
@section{Matching Sequences} @section{Matching Sequences}
A better @scheme[rotate] macro would allow any number of identifiers, A better @racket[rotate] macro would allow any number of identifiers,
instead of just two or three. To match a use of @scheme[rotate] with instead of just two or three. To match a use of @racket[rotate] with
any number of identifiers, we need a pattern form that has something any number of identifiers, we need a pattern form that has something
like a Kleene star. In a Scheme macro pattern, a star is written as like a Kleene star. In a Racket macro pattern, a star is written as
@scheme[...]. @racket[...].
To implement @scheme[rotate] with @scheme[...], we need a base case to To implement @racket[rotate] with @racket[...], we need a base case to
handle a single identifier, and an inductive case to handle more than handle a single identifier, and an inductive case to handle more than
one identifier: one identifier:
@schemeblock[ @racketblock[
(define-syntax rotate (define-syntax rotate
(syntax-rules () (syntax-rules ()
[(rotate a) (void)] [(rotate a) (void)]
@ -206,19 +206,19 @@ one identifier:
(rotate b c ...))])) (rotate b c ...))]))
] ]
When a pattern variable like @scheme[c] is followed by @scheme[...] in When a pattern variable like @racket[c] is followed by @racket[...] in
a pattern, then it must be followed by @scheme[...] in a template, a pattern, then it must be followed by @racket[...] in a template,
too. The pattern variable effectively matches a sequence of zero or too. The pattern variable effectively matches a sequence of zero or
more forms, and it is replaced in the template by the same sequence. more forms, and it is replaced in the template by the same sequence.
Both versions of @scheme[rotate] so far are a bit inefficient, since Both versions of @racket[rotate] so far are a bit inefficient, since
pairwise swapping keeps moving the value from the first variable into pairwise swapping keeps moving the value from the first variable into
every variable in the sequence until it arrives at the last one. A every variable in the sequence until it arrives at the last one. A
more efficient @scheme[rotate] would move the first value directly to more efficient @racket[rotate] would move the first value directly to
the last variable. We can use @scheme[...] patterns to implement the the last variable. We can use @racket[...] patterns to implement the
more efficient variant using a helper macro: more efficient variant using a helper macro:
@schemeblock[ @racketblock[
(define-syntax rotate (define-syntax rotate
(syntax-rules () (syntax-rules ()
[(rotate a c ...) [(rotate a c ...)
@ -232,18 +232,18 @@ more efficient variant using a helper macro:
(set! to0 tmp))])) (set! to0 tmp))]))
] ]
In the @scheme[shift-to] macro, @scheme[...] in the template follows In the @racket[shift-to] macro, @racket[...] in the template follows
@scheme[(set! to from)], which causes the @scheme[(set! to from)] @racket[(set! to from)], which causes the @racket[(set! to from)]
expression to be duplicated as many times as necessary to use each expression to be duplicated as many times as necessary to use each
identifier matched in the @scheme[to] and @scheme[from] identifier matched in the @racket[to] and @racket[from]
sequences. (The number of @scheme[to] and @scheme[from] matches must sequences. (The number of @racket[to] and @racket[from] matches must
be the same, otherwise the macro expansion fails with an error.) be the same, otherwise the macro expansion fails with an error.)
@; ---------------------------------------- @; ----------------------------------------
@section{Identifier Macros} @section{Identifier Macros}
Given our macro definitions, the @scheme[swap] or @scheme[rotate] Given our macro definitions, the @racket[swap] or @racket[rotate]
identifiers must be used after an open parenthesis, otherwise a syntax identifiers must be used after an open parenthesis, otherwise a syntax
error is reported: error is reported:
@ -252,13 +252,13 @@ error is reported:
@interaction[(+ swap 3)] @interaction[(+ swap 3)]
An @deftech{identifier macro} works in any expression. For example, we An @deftech{identifier macro} works in any expression. For example, we
can define @scheme[clock] as an identifier macro that expands to can define @racket[clock] as an identifier macro that expands to
@scheme[(get-clock)], so @scheme[(+ clock 3)] would expand to @racket[(get-clock)], so @racket[(+ clock 3)] would expand to
@scheme[(+ (get-clock) 3)]. An identifier macro also cooperates with @racket[(+ (get-clock) 3)]. An identifier macro also cooperates with
@scheme[set!], and we can define @scheme[clock] so that @scheme[(set! @racket[set!], and we can define @racket[clock] so that @racket[(set!
clock 3)] expands to @scheme[(put-clock! 3)]. clock 3)] expands to @racket[(put-clock! 3)].
The @scheme[syntax-id-rules] form is like @scheme[syntax-rules], but The @racket[syntax-id-rules] form is like @racket[syntax-rules], but
it creates a transformer that acts as an identifier macro: it creates a transformer that acts as an identifier macro:
@specform[#:literals (syntax-id-rules) @specform[#:literals (syntax-id-rules)
@ -267,12 +267,12 @@ it creates a transformer that acts as an identifier macro:
[pattern template] [pattern template]
...))] ...))]
Unlike a @scheme[syntax-rules] form, the @scheme[_pattern]s are not Unlike a @racket[syntax-rules] form, the @racket[_pattern]s are not
required to start with an open parenthesis. Also, @scheme[set!] is required to start with an open parenthesis. Also, @racket[set!] is
typically used as a literal to match a use of @scheme[set!] in the typically used as a literal to match a use of @racket[set!] in the
pattern (as opposed to being a pattern variable. pattern (as opposed to being a pattern variable.
@schemeblock[ @racketblock[
(define-syntax clock (define-syntax clock
(syntax-id-rules (set!) (syntax-id-rules (set!)
[(set! clock e) (put-clock! e)] [(set! clock e) (put-clock! e)]
@ -280,29 +280,29 @@ pattern (as opposed to being a pattern variable.
[clock (get-clock)])) [clock (get-clock)]))
] ]
The @scheme[(clock a ...)] pattern is needed because, when an The @racket[(clock a ...)] pattern is needed because, when an
identifier macro is used after an open parenthesis, the macro identifier macro is used after an open parenthesis, the macro
transformer is given the whole form, like with a non-identifier macro. transformer is given the whole form, like with a non-identifier macro.
Put another way, the @scheme[syntax-rules] form is essentially a Put another way, the @racket[syntax-rules] form is essentially a
special case of the @scheme[syntax-id-rules] form with errors in the special case of the @racket[syntax-id-rules] form with errors in the
@scheme[set!] and lone-identifier cases. @racket[set!] and lone-identifier cases.
@; ---------------------------------------- @; ----------------------------------------
@section{Macro-Generating Macros} @section{Macro-Generating Macros}
Suppose that we have many identifier like @scheme[clock] that we'd Suppose that we have many identifier like @racket[clock] that we'd
like to redirect to accessor and mutator functions like like to redirect to accessor and mutator functions like
@scheme[get-clock] and @scheme[put-clock!]. We'd like to be able to @racket[get-clock] and @racket[put-clock!]. We'd like to be able to
just write just write
@schemeblock[ @racketblock[
(define-get/put-id clock get-clock put-clock!) (define-get/put-id clock get-clock put-clock!)
] ]
Naturally, we can implement @scheme[define-get/put-id] as a macro: Naturally, we can implement @racket[define-get/put-id] as a macro:
@schemeblock[ @racketblock[
(define-syntax-rule (define-get/put-id id get put!) (define-syntax-rule (define-get/put-id id get put!)
(define-syntax id (define-syntax id
(syntax-id-rules (set!) (syntax-id-rules (set!)
@ -311,25 +311,25 @@ Naturally, we can implement @scheme[define-get/put-id] as a macro:
[id (get)]))) [id (get)])))
] ]
The @scheme[define-get/put-id] macro is a @deftech{macro-generating The @racket[define-get/put-id] macro is a @deftech{macro-generating
macro}. The only non-obvious part of its definition is the macro}. The only non-obvious part of its definition is the
@scheme[(... ...)], which ``quotes'' @scheme[...] so that it takes its @racket[(... ...)], which ``quotes'' @racket[...] so that it takes its
usual role in the generated macro, instead of the generating macro. usual role in the generated macro, instead of the generating macro.
@; ---------------------------------------- @; ----------------------------------------
@section[#:tag "pattern-macro-example"]{Extended Example: Call-by-Reference Functions} @section[#:tag "pattern-macro-example"]{Extended Example: Call-by-Reference Functions}
We can use pattern-matching macros to add a form to Scheme We can use pattern-matching macros to add a form to Racket
for defining first-order @deftech{call-by-reference} functions. When a for defining first-order @deftech{call-by-reference} functions. When a
call-by-reference function body mutates its formal argument, the call-by-reference function body mutates its formal argument, the
mutation applies to variables that are supplied as actual arguments in mutation applies to variables that are supplied as actual arguments in
a call to the function. a call to the function.
For example, if @scheme[define-cbr] is like @scheme[define] except For example, if @racket[define-cbr] is like @racket[define] except
that it defines a call-by-reference function, then that it defines a call-by-reference function, then
@schemeblock[ @racketblock[
(define-cbr (f a b) (define-cbr (f a b)
(swap a b)) (swap a b))
@ -338,35 +338,35 @@ that it defines a call-by-reference function, then
(list x y)) (list x y))
] ]
produces @schemeresult[(2 1)]. produces @racketresult[(2 1)].
We will implement call-by-reference functions by having function calls We will implement call-by-reference functions by having function calls
supply accessor and mutators for the arguments, instead of supplying supply accessor and mutators for the arguments, instead of supplying
argument values directly. In particular, for the function @scheme[f] argument values directly. In particular, for the function @racket[f]
above, we'll generate above, we'll generate
@schemeblock[ @racketblock[
(define (do-f get-a get-b put-a! put-b!) (define (do-f get-a get-b put-a! put-b!)
(define-get/put-id a get-a put-a!) (define-get/put-id a get-a put-a!)
(define-get/put-id b get-b put-b!) (define-get/put-id b get-b put-b!)
(swap a b)) (swap a b))
] ]
and redirect a function call @scheme[(f x y)] to and redirect a function call @racket[(f x y)] to
@schemeblock[ @racketblock[
(do-f (lambda () x) (do-f (lambda () x)
(lambda () y) (lambda () y)
(lambda (v) (set! x v)) (lambda (v) (set! x v))
(lambda (v) (set! y v))) (lambda (v) (set! y v)))
] ]
Clearly, then @scheme[define-cbr] is a macro-generating macro, which Clearly, then @racket[define-cbr] is a macro-generating macro, which
binds @scheme[f] to a macro that expands to a call of @scheme[do-f]. binds @racket[f] to a macro that expands to a call of @racket[do-f].
That is, @scheme[(define-cbr (f a b) (swap ab))] needs to generate the That is, @racket[(define-cbr (f a b) (swap ab))] needs to generate the
definition definition
@schemeblock[ @racketblock[
(define-syntax f (define-syntax f
(syntax-rules () (syntax-rules ()
[(id actual ...) [(id actual ...)
@ -377,13 +377,13 @@ definition
...)])) ...)]))
] ]
At the same time, @scheme[define-cbr] needs to define @scheme[do-f] At the same time, @racket[define-cbr] needs to define @racket[do-f]
using the body of @scheme[f], this second part is slightly more using the body of @racket[f], this second part is slightly more
complex, so we defer most it to a @scheme[define-for-cbr] helper complex, so we defer most it to a @racket[define-for-cbr] helper
module, which lets us write @scheme[define-cbr] easily enough: module, which lets us write @racket[define-cbr] easily enough:
@schemeblock[ @racketblock[
(define-syntax-rule (define-cbr (id arg ...) body) (define-syntax-rule (define-cbr (id arg ...) body)
(begin (begin
(define-syntax id (define-syntax id
@ -399,34 +399,34 @@ module, which lets us write @scheme[define-cbr] easily enough:
body))) body)))
] ]
Our remaining task is to define @scheme[define-for-cbr] so that it Our remaining task is to define @racket[define-for-cbr] so that it
converts converts
@schemeblock[ @racketblock[
(define-for-cbr do-f (a b) () (swap a b)) (define-for-cbr do-f (a b) () (swap a b))
] ]
to the function definition @scheme[do-f] above. Most of the work is to the function definition @racket[do-f] above. Most of the work is
generating a @scheme[define-get/put-id] declaration for each argument, generating a @racket[define-get/put-id] declaration for each argument,
@scheme[a] ad @scheme[b], and putting them before the body. Normally, @racket[a] ad @racket[b], and putting them before the body. Normally,
that's an easy task for @scheme[...] in a pattern and template, but that's an easy task for @racket[...] in a pattern and template, but
this time there's a catch: we need to generate the names this time there's a catch: we need to generate the names
@scheme[get-a] and @scheme[put-a!] as well as @scheme[get-b] and @racket[get-a] and @racket[put-a!] as well as @racket[get-b] and
@scheme[put-b!], and the pattern language provides no way to @racket[put-b!], and the pattern language provides no way to
synthesize identifiers based on existing identifiers. synthesize identifiers based on existing identifiers.
As it turns out, lexical scope gives us a way around this problem. The As it turns out, lexical scope gives us a way around this problem. The
trick is to iterate expansions of @scheme[define-for-cbr] once for trick is to iterate expansions of @racket[define-for-cbr] once for
each argument in the function, and that's why @scheme[define-cbr] each argument in the function, and that's why @racket[define-cbr]
starts with an apparently useless @scheme[()] after the argument starts with an apparently useless @racket[()] after the argument
list. We need to keep track of all the arguments seen so far and the list. We need to keep track of all the arguments seen so far and the
@scheme[get] and @scheme[put] names generated for each, in addition to @racket[get] and @racket[put] names generated for each, in addition to
the arguments left to process. After we've processed all the the arguments left to process. After we've processed all the
identifiers, then we have all the names we need. identifiers, then we have all the names we need.
Here is the definition of @scheme[define-for-cbr]: Here is the definition of @racket[define-for-cbr]:
@schemeblock[ @racketblock[
(define-syntax define-for-cbr (define-syntax define-for-cbr
(syntax-rules () (syntax-rules ()
[(define-for-cbr do-f (id0 id ...) [(define-for-cbr do-f (id0 id ...)
@ -442,7 +442,7 @@ Here is the definition of @scheme[define-for-cbr]:
Step-by-step, expansion proceeds as follows: Step-by-step, expansion proceeds as follows:
@schemeblock[ @racketblock[
(define-for-cbr do-f (a b) (define-for-cbr do-f (a b)
() (swap a b)) () (swap a b))
=> (define-for-cbr do-f (b) => (define-for-cbr do-f (b)
@ -455,11 +455,11 @@ Step-by-step, expansion proceeds as follows:
(swap a b)) (swap a b))
] ]
The ``subscripts'' on @scheme[get_1], @scheme[get_2], The ``subscripts'' on @racket[get_1], @racket[get_2],
@scheme[put_1], and @scheme[put_2] are inserted by the macro @racket[put_1], and @racket[put_2] are inserted by the macro
expander to preserve lexical scope, since the @scheme[get] expander to preserve lexical scope, since the @racket[get]
generated by each iteration of @scheme[define-for-cbr] should not generated by each iteration of @racket[define-for-cbr] should not
bind the @scheme[get] generated by a different iteration. In bind the @racket[get] generated by a different iteration. In
other words, we are essentially tricking the macro expander into other words, we are essentially tricking the macro expander into
generating fresh names for us, but the technique illustrates some generating fresh names for us, but the technique illustrates some
of the surprising power of pattern-based macros with automatic of the surprising power of pattern-based macros with automatic
@ -467,17 +467,17 @@ lexical scope.
The last expression eventually expands to just The last expression eventually expands to just
@schemeblock[ @racketblock[
(define (do-f get_1 get_2 put_1 put_2) (define (do-f get_1 get_2 put_1 put_2)
(let ([tmp (get_1)]) (let ([tmp (get_1)])
(put_1 (get_2)) (put_1 (get_2))
(put_2 tmp))) (put_2 tmp)))
] ]
which implements the call-by-name function @scheme[f]. which implements the call-by-name function @racket[f].
To summarize, then, we can add call-by-reference functions to To summarize, then, we can add call-by-reference functions to
Scheme with just three small pattern-based macros: Racket with just three small pattern-based macros:
@scheme[define-cbr], @scheme[define-for-cbr], and @racket[define-cbr], @racket[define-for-cbr], and
@scheme[define-get/put-id]. @racket[define-get/put-id].

View File

@ -1,31 +1,31 @@
#lang scribble/doc #lang scribble/doc
@(require scribble/manual @(require scribble/manual
"guide-utils.ss" "guide-utils.ss"
(for-label scheme/flonum scheme/unsafe/ops)) (for-label racket/flonum racket/unsafe/ops))
@title[#:tag "performance"]{Performance} @title[#:tag "performance"]{Performance}
Alan Perlis famously quipped ``Lisp programmers know the value of Alan Perlis famously quipped ``Lisp programmers know the value of
everything and the cost of nothing.'' A Scheme programmer knows, for everything and the cost of nothing.'' A Racket programmer knows, for
example, that a @scheme[lambda] anywhere in a program produces a value example, that a @racket[lambda] anywhere in a program produces a value
that is closed over it lexical environment---but how much does that is closed over it lexical environment---but how much does
allocating that value cost? While most programmers have a reasonable allocating that value cost? While most programmers have a reasonable
grasp of the cost of various operations and data structures at the grasp of the cost of various operations and data structures at the
machine level, the gap between the Scheme language model and the machine level, the gap between the Racket language model and the
underlying computing machinery can be quite large. underlying computing machinery can be quite large.
In this chapter, we narrow the gap by explaining details of the PLT In this chapter, we narrow the gap by explaining details of the
Scheme compiler and run-time system and how they affect the run-time Racket compiler and run-time system and how they affect the run-time
and memory performance of Scheme code. and memory performance of Racket code.
@; ---------------------------------------------------------------------- @; ----------------------------------------------------------------------
@section[#:tag "JIT"]{The Bytecode and Just-in-Time (JIT) Compilers} @section[#:tag "JIT"]{The Bytecode and Just-in-Time (JIT) Compilers}
Every definition or expression to be evaluated by Scheme is compiled Every definition or expression to be evaluated by Racket is compiled
to an internal bytecode format. In interactive mode, this compilation to an internal bytecode format. In interactive mode, this compilation
occurs automatically and on-the-fly. Tools like @exec{mzc} and occurs automatically and on-the-fly. Tools like @exec{raco make} and
@exec{setup-plt} marshal compiled bytecode to a file, so that you do @exec{raco setup} marshal compiled bytecode to a file, so that you do
not have to compile from source every time that you run a not have to compile from source every time that you run a
program. (Most of the time required to compile a file is actually in program. (Most of the time required to compile a file is actually in
macro expansion; generating bytecode from fully expanded code is macro expansion; generating bytecode from fully expanded code is
@ -34,9 +34,9 @@ generating bytecode files.
The bytecode compiler applies all standard optimizations, such as The bytecode compiler applies all standard optimizations, such as
constant propagation, constant folding, inlining, and dead-code constant propagation, constant folding, inlining, and dead-code
elimination. For example, in an environment where @scheme[+] has its elimination. For example, in an environment where @racket[+] has its
usual binding, the expression @scheme[(let ([x 1][y (lambda () 4)]) (+ usual binding, the expression @racket[(let ([x 1][y (lambda () 4)]) (+
1 (y)))] is compiled the same as the constant @scheme[5]. 1 (y)))] is compiled the same as the constant @racket[5].
On some platforms, bytecode is further compiled to native code via a On some platforms, bytecode is further compiled to native code via a
@deftech{just-in-time} or @deftech{JIT} compiler. The @tech{JIT} @deftech{just-in-time} or @deftech{JIT} compiler. The @tech{JIT}
@ -44,13 +44,13 @@ compiler substantially speeds programs that execute tight loops,
arithmetic on small integers, and arithmetic on inexact real arithmetic on small integers, and arithmetic on inexact real
numbers. Currently, @tech{JIT} compilation is supported for x86, numbers. Currently, @tech{JIT} compilation is supported for x86,
x86_64 (a.k.a. AMD64), and 32-bit PowerPC processors. The @tech{JIT} x86_64 (a.k.a. AMD64), and 32-bit PowerPC processors. The @tech{JIT}
compiler can be disabled via the @scheme[eval-jit-enabled] parameter compiler can be disabled via the @racket[eval-jit-enabled] parameter
or the @DFlag{no-jit}/@Flag{j} command-line flag for @exec{mzscheme}. or the @DFlag{no-jit}/@Flag{j} command-line flag for @exec{racket}.
The @tech{JIT} compiler works incrementally as functions are applied, The @tech{JIT} compiler works incrementally as functions are applied,
but the @tech{JIT} compiler makes only limited use of run-time but the @tech{JIT} compiler makes only limited use of run-time
information when compiling procedures, since the code for a given information when compiling procedures, since the code for a given
module body or @scheme[lambda] abstraction is compiled only once. The module body or @racket[lambda] abstraction is compiled only once. The
@tech{JIT}'s granularity of compilation is a single procedure body, @tech{JIT}'s granularity of compilation is a single procedure body,
not counting the bodies of any lexically nested procedures. The not counting the bodies of any lexically nested procedures. The
overhead for @tech{JIT} compilation is normally so small that it is overhead for @tech{JIT} compilation is normally so small that it is
@ -61,33 +61,33 @@ difficult to detect.
@section{Modules and Performance} @section{Modules and Performance}
The module system aids optimization by helping to ensure that The module system aids optimization by helping to ensure that
identifiers have the usual bindings. That is, the @scheme[+] provided identifiers have the usual bindings. That is, the @racket[+] provided
by @schememodname[scheme/base] can be recognized by the compiler and by @racketmodname[racket/base] can be recognized by the compiler and
inlined, which is especially important for @tech{JIT}-compiled code. inlined, which is especially important for @tech{JIT}-compiled code.
In contrast, in a traditional interactive Scheme system, the top-level In contrast, in a traditional interactive Racket system, the top-level
@scheme[+] binding might be redefined, so the compiler cannot assume a @racket[+] binding might be redefined, so the compiler cannot assume a
fixed @scheme[+] binding (unless special flags or declarations fixed @racket[+] binding (unless special flags or declarations
act as a poor-man's module system to indicate otherwise). act as a poor-man's module system to indicate otherwise).
Even in the top-level environment, importing with @scheme[require] Even in the top-level environment, importing with @racket[require]
enables some inlining optimizations. Although a @scheme[+] definition enables some inlining optimizations. Although a @racket[+] definition
at the top level might shadow an imported @scheme[+], the shadowing at the top level might shadow an imported @racket[+], the shadowing
definition applies only to expressions evaluated later. definition applies only to expressions evaluated later.
Within a module, inlining and constant-propagation optimizations take Within a module, inlining and constant-propagation optimizations take
additional advantage of the fact that definitions within a module additional advantage of the fact that definitions within a module
cannot be mutated when no @scheme[set!] is visable at compile cannot be mutated when no @racket[set!] is visable at compile
time. Such optimizations are unavailable in the top-level time. Such optimizations are unavailable in the top-level
environment. Although this optimization within modules is important environment. Although this optimization within modules is important
for performance, it hinders some forms of interactive development and for performance, it hinders some forms of interactive development and
exploration. The @scheme[compile-enforce-module-constants] parameter exploration. The @racket[compile-enforce-module-constants] parameter
disables the @tech{JIT} compiler's assumptions about module disables the @tech{JIT} compiler's assumptions about module
definitions when interactive exploration is more important. See definitions when interactive exploration is more important. See
@secref["module-set"] for more information. @secref["module-set"] for more information.
Currently, the compiler does not attempt to inline or propagate Currently, the compiler does not attempt to inline or propagate
constants across module boundary, except for exports of the built-in constants across module boundaries, except for exports of the built-in
modules (such as the one that originally provides @scheme[+]). modules (such as the one that originally provides @racket[+]).
The later section @secref["letrec-performance"] provides some The later section @secref["letrec-performance"] provides some
additional caveats concerning inlining of module bindings. additional caveats concerning inlining of module bindings.
@ -100,7 +100,7 @@ When the compiler detects a function call to an immediately visible
function, it generates more efficient code than for a generic call, function, it generates more efficient code than for a generic call,
especially for tail calls. For example, given the program especially for tail calls. For example, given the program
@schemeblock[ @racketblock[
(letrec ([odd (lambda (x) (letrec ([odd (lambda (x)
(if (zero? x) (if (zero? x)
#f #f
@ -112,23 +112,23 @@ especially for tail calls. For example, given the program
(odd 40000000)) (odd 40000000))
] ]
the compiler can detect the @scheme[odd]--@scheme[even] loop and the compiler can detect the @racket[odd]--@racket[even] loop and
produce code that runs much faster via loop unrolling and related produce code that runs much faster via loop unrolling and related
optimizations. optimizations.
Within a module form, @scheme[define]d variables are lexically scoped Within a module form, @racket[define]d variables are lexically scoped
like @scheme[letrec] bindings, and definitions within a module like @racket[letrec] bindings, and definitions within a module
therefore permit call optimizations, so therefore permit call optimizations, so
@schemeblock[ @racketblock[
(define (odd x) ....) (define (odd x) ....)
(define (even x) ....) (define (even x) ....)
] ]
within a module would perform the same as the @scheme[letrec] version. within a module would perform the same as the @racket[letrec] version.
Primitive operations like @scheme[pair?], @scheme[car], and Primitive operations like @racket[pair?], @racket[car], and
@scheme[cdr] are inlined at the machine-code level by the @tech{JIT} @racket[cdr] are inlined at the machine-code level by the @tech{JIT}
compiler. See also the later section @secref["fixnums+flonums"] for compiler. See also the later section @secref["fixnums+flonums"] for
information about inlined arithmetic operations. information about inlined arithmetic operations.
@ -136,11 +136,11 @@ information about inlined arithmetic operations.
@section{Mutation and Performance} @section{Mutation and Performance}
Using @scheme[set!] to mutate a variable can lead to bad Using @racket[set!] to mutate a variable can lead to bad
performance. For example, the microbenchmark performance. For example, the microbenchmark
@schememod[ @racketmod[
scheme/base racket/base
(define (subtract-one x) (define (subtract-one x)
(set! x (sub1 x)) (set! x (sub1 x))
@ -155,8 +155,8 @@ scheme/base
runs much more slowly than the equivalent runs much more slowly than the equivalent
@schememod[ @racketmod[
scheme/base racket/base
(define (subtract-one x) (define (subtract-one x)
(sub1 x)) (sub1 x))
@ -168,16 +168,16 @@ scheme/base
(loop (subtract-one n))))) (loop (subtract-one n)))))
] ]
In the first variant, a new location is allocated for @scheme[x] on In the first variant, a new location is allocated for @racket[x] on
every iteration, leading to poor performance. A more clever compiler every iteration, leading to poor performance. A more clever compiler
could unravel the use of @scheme[set!] in the first example, but since could unravel the use of @racket[set!] in the first example, but since
mutation is discouraged (see @secref["using-set!"]), the compiler's mutation is discouraged (see @secref["using-set!"]), the compiler's
effort is spent elsewhere. effort is spent elsewhere.
More significantly, mutation can obscure bindings where inlining and More significantly, mutation can obscure bindings where inlining and
constant-propagation might otherwise apply. For example, in constant-propagation might otherwise apply. For example, in
@schemeblock[ @racketblock[
(let ([minus1 #f]) (let ([minus1 #f])
(set! minus1 sub1) (set! minus1 sub1)
(let loop ([n 4000000]) (let loop ([n 4000000])
@ -186,14 +186,14 @@ constant-propagation might otherwise apply. For example, in
(loop (minus1 n))))) (loop (minus1 n)))))
] ]
the @scheme[set!] obscures the fact that @scheme[minus1] is just the @racket[set!] obscures the fact that @racket[minus1] is just
another name for the built-in @scheme[sub1]. another name for the built-in @racket[sub1].
@; ---------------------------------------------------------------------- @; ----------------------------------------------------------------------
@section[#:tag "letrec-performance"]{@scheme[letrec] Performance} @section[#:tag "letrec-performance"]{@racket[letrec] Performance}
When @scheme[letrec] is used to bind only procedures and literals, When @racket[letrec] is used to bind only procedures and literals,
then the compiler can treat the bindings in an optimal manner, then the compiler can treat the bindings in an optimal manner,
compiling uses of the bindings efficiently. When other kinds of compiling uses of the bindings efficiently. When other kinds of
bindings are mixed with procedures, the compiler may be less able to bindings are mixed with procedures, the compiler may be less able to
@ -201,7 +201,7 @@ determine the control flow.
For example, For example,
@schemeblock[ @racketblock[
(letrec ([loop (lambda (x) (letrec ([loop (lambda (x)
(if (zero? x) (if (zero? x)
'done 'done
@ -213,7 +213,7 @@ For example,
likely compiles to less efficient code than likely compiles to less efficient code than
@schemeblock[ @racketblock[
(letrec ([loop (lambda (x) (letrec ([loop (lambda (x)
(if (zero? x) (if (zero? x)
'done 'done
@ -223,13 +223,13 @@ likely compiles to less efficient code than
] ]
In the first case, the compiler likely does not know that In the first case, the compiler likely does not know that
@scheme[display] does not call @scheme[loop]. If it did, then @racket[display] does not call @racket[loop]. If it did, then
@scheme[loop] might refer to @scheme[next] before the binding is @racket[loop] might refer to @racket[next] before the binding is
available. available.
This caveat about @scheme[letrec] also applies to definitions of This caveat about @racket[letrec] also applies to definitions of
functions and constants within modules. A definition sequence in a functions and constants within modules. A definition sequence in a
module body is analogous to a sequence of @scheme[letrec] bindings, module body is analogous to a sequence of @racket[letrec] bindings,
and non-constant expressions in a module body can interfere with the and non-constant expressions in a module body can interfere with the
optimization of references to later bindings. optimization of references to later bindings.
@ -247,14 +247,14 @@ correspond to 64-bit IEEE floating-point numbers on all platforms.
Inlined fixnum and flonum arithmetic operations are among the most Inlined fixnum and flonum arithmetic operations are among the most
important advantages of the @tech{JIT} compiler. For example, when important advantages of the @tech{JIT} compiler. For example, when
@scheme[+] is applied to two arguments, the generated machine code @racket[+] is applied to two arguments, the generated machine code
tests whether the two arguments are fixnums, and if so, it uses the tests whether the two arguments are fixnums, and if so, it uses the
machine's instruction to add the numbers (and check for overflow). If machine's instruction to add the numbers (and check for overflow). If
the two numbers are not fixnums, then the next check whether whether the two numbers are not fixnums, then it checks whether whether
both are flonums; in that case, the machine's floating-point both are flonums; in that case, the machine's floating-point
operations are used directly. For functions that take any number of operations are used directly. For functions that take any number of
arguments, such as @scheme[+], inlining works for two or more arguments, such as @racket[+], inlining works for two or more
arguments (except for @scheme[-], whose one-argument case is also arguments (except for @racket[-], whose one-argument case is also
inlined) when the arguments are either all fixnums or all flonums. inlined) when the arguments are either all fixnums or all flonums.
Flonums are typically @defterm{boxed}, which means that memory is Flonums are typically @defterm{boxed}, which means that memory is
@ -267,23 +267,23 @@ typically cheap to use.
@margin-note{See @secref["effective-futures"] for an example use of @margin-note{See @secref["effective-futures"] for an example use of
@tech{flonum}-specific operations.} @tech{flonum}-specific operations.}
The @schememodname[scheme/flonum] library provides flonum-specific The @racketmodname[racket/flonum] library provides flonum-specific
operations, and combinations of flonum operations allow the @tech{JIT} operations, and combinations of flonum operations allow the @tech{JIT}
compiler to generate code that avoids boxing and unboxing intermediate compiler to generate code that avoids boxing and unboxing intermediate
results. Besides results within immediate combinations, results. Besides results within immediate combinations,
flonum-specific results that are bound with @scheme[let] and consumed flonum-specific results that are bound with @racket[let] and consumed
by a later flonum-specific operation are unboxed within temporary by a later flonum-specific operation are unboxed within temporary
storage. Finally, the compiler can detect some flonum-valued loop storage. Finally, the compiler can detect some flonum-valued loop
accumulators and avoid boxing of the accumulator. The bytecode accumulators and avoid boxing of the accumulator. The bytecode
decompiler (see @secref[#:doc '(lib "scribblings/mzc/mzc.scrbl") decompiler (see @secref[#:doc '(lib "scribblings/mzc/mzc.scrbl")
"decompile"]) annotates combinations where the JIT can avoid boxes with "decompile"]) annotates combinations where the JIT can avoid boxes with
@schemeidfont{#%flonum}, @schemeidfont{#%as-flonum}, and @racketidfont{#%flonum}, @racketidfont{#%as-flonum}, and
@schemeidfont{#%from-flonum}. @racketidfont{#%from-flonum}.
@margin-note{Unboxing of local bindings and accumualtors is not @margin-note{Unboxing of local bindings and accumualtors is not
supported by the JIT for PowerPC.} supported by the JIT for PowerPC.}
The @schememodname[scheme/unsafe/ops] library provides unchecked The @racketmodname[racket/unsafe/ops] library provides unchecked
fixnum- and flonum-specific operations. Unchecked flonum-specific fixnum- and flonum-specific operations. Unchecked flonum-specific
operations allow unboxing, and sometimes they allow the compiler to operations allow unboxing, and sometimes they allow the compiler to
reorder expressions to improve performance. See also reorder expressions to improve performance. See also
@ -293,10 +293,10 @@ reorder expressions to improve performance. See also
@section[#:tag "unchecked-unsafe"]{Unchecked, Unsafe Operations} @section[#:tag "unchecked-unsafe"]{Unchecked, Unsafe Operations}
The @schememodname[scheme/unsafe/ops] library provides functions that The @racketmodname[racket/unsafe/ops] library provides functions that
are like other functions in @schememodname[scheme/base], but they are like other functions in @racketmodname[racket/base], but they
assume (instead of checking) that provided arguments are of the right assume (instead of checking) that provided arguments are of the right
type. For example, @scheme[unsafe-vector-ref] accesses an element from type. For example, @racket[unsafe-vector-ref] accesses an element from
a vector without checking that its first argument is actually a vector a vector without checking that its first argument is actually a vector
and without checking that the given index is in bounds. For tight and without checking that the given index is in bounds. For tight
loops that use these functions, avoiding checks can sometimes speed loops that use these functions, avoiding checks can sometimes speed
@ -304,20 +304,20 @@ the computation, though the benefits vary for different unchecked
functions and different contexts. functions and different contexts.
Beware that, as ``unsafe'' in the library and function names suggest, Beware that, as ``unsafe'' in the library and function names suggest,
misusing the exports of @schememodname[scheme/unsafe/ops] can lead to misusing the exports of @racketmodname[racket/unsafe/ops] can lead to
crashes or memory corruption. crashes or memory corruption.
@; ---------------------------------------------------------------------- @; ----------------------------------------------------------------------
@section[#:tag "gc-perf"]{Memory Management} @section[#:tag "gc-perf"]{Memory Management}
PLT Scheme is available in two variants: @deftech{3m} and The Racket implementation is available in two variants: @deftech{3m} and
@deftech{CGC}. The @tech{3m} variant uses a modern, @deftech{CGC}. The @tech{3m} variant uses a modern,
@deftech{generational garbage collector} that makes allocation @deftech{generational garbage collector} that makes allocation
relatively cheap for short-lived objects. The @tech{CGC} variant uses relatively cheap for short-lived objects. The @tech{CGC} variant uses
a @deftech{conservative garbage collector} which facilitates a @deftech{conservative garbage collector} which facilitates
interaction with C code at the expense of both precision and speed for interaction with C code at the expense of both precision and speed for
Scheme memory management. The 3m variant is the standard one. Racket memory management. The 3m variant is the standard one.
Although memory allocation is reasonably cheap, avoiding allocation Although memory allocation is reasonably cheap, avoiding allocation
altogether is normally faster. One particular place where allocation altogether is normally faster. One particular place where allocation
@ -325,7 +325,7 @@ can be avoided sometimes is in @deftech{closures}, which are the
run-time representation of functions that contain free variables. run-time representation of functions that contain free variables.
For example, For example,
@schemeblock[ @racketblock[
(let loop ([n 40000000][prev-thunk (lambda () #f)]) (let loop ([n 40000000][prev-thunk (lambda () #f)])
(if (zero? n) (if (zero? n)
(prev-thunk) (prev-thunk)
@ -333,13 +333,13 @@ For example,
(lambda () n)))) (lambda () n))))
] ]
allocates a closure on every iteration, since @scheme[(lambda () n)] allocates a closure on every iteration, since @racket[(lambda () n)]
effectively saves @scheme[n]. effectively saves @racket[n].
The compiler can eliminate many closures automatically. For example, The compiler can eliminate many closures automatically. For example,
in in
@schemeblock[ @racketblock[
(let loop ([n 40000000][prev-val #f]) (let loop ([n 40000000][prev-val #f])
(let ([prev-thunk (lambda () n)]) (let ([prev-thunk (lambda () n)])
(if (zero? n) (if (zero? n)
@ -347,10 +347,10 @@ in
(loop (sub1 n) (prev-thunk))))) (loop (sub1 n) (prev-thunk)))))
] ]
no closure is ever allocated for @scheme[prev-thunk], because its only no closure is ever allocated for @racket[prev-thunk], because its only
application is visible, and so it is inlined. Similarly, in application is visible, and so it is inlined. Similarly, in
@schemeblock[ @racketblock[
(let n-loop ([n 400000]) (let n-loop ([n 400000])
(if (zero? n) (if (zero? n)
'done 'done
@ -360,9 +360,9 @@ application is visible, and so it is inlined. Similarly, in
(m-loop (sub1 m)))))) (m-loop (sub1 m))))))
] ]
then the expansion of the @scheme[let] form to implement then the expansion of the @racket[let] form to implement
@scheme[m-loop] involves a closure over @scheme[n], but the compiler @racket[m-loop] involves a closure over @racket[n], but the compiler
automatically converts the closure to pass itself @scheme[n] as an automatically converts the closure to pass itself @racket[n] as an
argument instead. argument instead.
@; ---------------------------------------------------------------------- @; ----------------------------------------------------------------------

View File

@ -4,34 +4,34 @@
"guide-utils.ss") "guide-utils.ss")
@(define check-eval (make-base-eval)) @(define check-eval (make-base-eval))
@(interaction-eval #:eval check-eval (require (for-syntax scheme/base))) @(interaction-eval #:eval check-eval (require (for-syntax racket/base)))
@(define-syntax-rule (schemeblock/eval #:eval e body ...) @(define-syntax-rule (racketblock/eval #:eval e body ...)
(begin (begin
(interaction-eval #:eval e body) ... (interaction-eval #:eval e body) ...
(schemeblock body ...))) (racketblock body ...)))
@title[#:tag "proc-macros" #:style 'toc]{General Macro Transformers} @title[#:tag "proc-macros" #:style 'toc]{General Macro Transformers}
The @scheme[define-syntax] form creates a @deftech{transformer The @racket[define-syntax] form creates a @deftech{transformer
binding} for an identifier, which is a binding that can be used at binding} for an identifier, which is a binding that can be used at
compile time while expanding expressions to be evaluated at run time. compile time while expanding expressions to be evaluated at run time.
The compile-time value associated with a transformer binding can be The compile-time value associated with a transformer binding can be
anything; if it is a procedure of one argument, then the binding is anything; if it is a procedure of one argument, then the binding is
used as a macro, and the procedure is the @deftech{macro transformer}. used as a macro, and the procedure is the @deftech{macro transformer}.
The @scheme[syntax-rules] and @scheme[syntax-id-rules] forms are The @racket[syntax-rules] and @racket[syntax-id-rules] forms are
macros that expand to procedure forms. For example, if you evaluate a macros that expand to procedure forms. For example, if you evaluate a
@scheme[syntax-rules] form directly (instead of placing on the @racket[syntax-rules] form directly (instead of placing on the
right-hand of a @scheme[define-syntax] form), the result is a right-hand of a @racket[define-syntax] form), the result is a
procedure: procedure:
@interaction[ @interaction[
(syntax-rules () [(nothing) something]) (syntax-rules () [(nothing) something])
] ]
Instead of using @scheme[syntax-rules], you can write your own macro Instead of using @racket[syntax-rules], you can write your own macro
transformer procedure directly using @scheme[lambda]. The argument to transformer procedure directly using @racket[lambda]. The argument to
the procedure is a values that represents the source form, and the the procedure is a values that represents the source form, and the
result of the procedure must be a value that represents the result of the procedure must be a value that represents the
replacement form. replacement form.
@ -45,37 +45,37 @@ replacement form.
The input and output of a macro transformer (i.e., source and The input and output of a macro transformer (i.e., source and
replacement forms) are represented as @deftech{syntax objects}. A replacement forms) are represented as @deftech{syntax objects}. A
syntax object contains symbols, lists, and constant values (such as syntax object contains symbols, lists, and constant values (such as
numbers) that essentially correspond to the @scheme[quote]d form of numbers) that essentially correspond to the @racket[quote]d form of
the expression. For example, a representation of the expression the expression. For example, a representation of the expression
@scheme[(+ 1 2)] contains the symbol @scheme['+] and the numbers @racket[(+ 1 2)] contains the symbol @racket['+] and the numbers
@scheme[1] and @scheme[2], all in a list. In addition to this quoted @racket[1] and @racket[2], all in a list. In addition to this quoted
content, a syntax object associates source-location and content, a syntax object associates source-location and
lexical-binding information with each part of the form. The lexical-binding information with each part of the form. The
source-location information is used when reporting syntax errors (for source-location information is used when reporting syntax errors (for
example), and the lexical-biding information allows the macro system example), and the lexical-biding information allows the macro system
to maintain lexical scope. To accommodate this extra information, the to maintain lexical scope. To accommodate this extra information, the
represention of the expression @scheme[(+ 1 2)] is not merely represention of the expression @racket[(+ 1 2)] is not merely
@scheme['(+ 1 2)], but a packaging of @scheme['(+ 1 2)] into a syntax @racket['(+ 1 2)], but a packaging of @racket['(+ 1 2)] into a syntax
object. object.
To create a literal syntax object, use the @scheme[syntax] form: To create a literal syntax object, use the @racket[syntax] form:
@interaction[ @interaction[
(eval:alts (#,(scheme syntax) (+ 1 2)) (syntax (+ 1 2))) (eval:alts (#,(racket syntax) (+ 1 2)) (syntax (+ 1 2)))
] ]
In the same way that @litchar{'} abbreviates @scheme[quote], In the same way that @litchar{'} abbreviates @racket[quote],
@litchar{#'} abbreviates @scheme[syntax]: @litchar{#'} abbreviates @racket[syntax]:
@interaction[ @interaction[
#'(+ 1 2) #'(+ 1 2)
] ]
A syntax object that contains just a symbol is an @deftech{identifier A syntax object that contains just a symbol is an @deftech{identifier
syntax object}. Scheme provides some additional operations specific to syntax object}. Racket provides some additional operations specific to
identifier syntax objects, including the @scheme[identifier?] identifier syntax objects, including the @racket[identifier?]
operation to detect identifiers. Most notably, operation to detect identifiers. Most notably,
@scheme[free-identifier=?] determines whether two identifiers refer @racket[free-identifier=?] determines whether two identifiers refer
to the same binding: to the same binding:
@interaction[ @interaction[
@ -83,7 +83,7 @@ to the same binding:
(identifier? #'(+ 1 2)) (identifier? #'(+ 1 2))
(free-identifier=? #'car #'cdr) (free-identifier=? #'car #'cdr)
(free-identifier=? #'car #'car) (free-identifier=? #'car #'car)
(require (only-in scheme/base [car also-car])) (require (only-in racket/base [car also-car]))
(free-identifier=? #'car #'also-car) (free-identifier=? #'car #'also-car)
(free-identifier=? #'car (let ([car 8]) (free-identifier=? #'car (let ([car 8])
#'car)) #'car))
@ -93,13 +93,13 @@ The last example above, in particular, illustrates how syntax objects
preserve lexical-context information. preserve lexical-context information.
To see the lists, symbols, numbers, @|etc| within a syntax object, use To see the lists, symbols, numbers, @|etc| within a syntax object, use
@scheme[syntax->datum]: @racket[syntax->datum]:
@interaction[ @interaction[
(syntax->datum #'(+ 1 2)) (syntax->datum #'(+ 1 2))
] ]
The @scheme[syntax-e] function is similar to @scheme[syntax->datum], The @racket[syntax-e] function is similar to @racket[syntax->datum],
but it unwraps a single layer of source-location and lexical-context but it unwraps a single layer of source-location and lexical-context
information, leaving sub-forms that have their own information wrapped information, leaving sub-forms that have their own information wrapped
as syntax objects: as syntax objects:
@ -108,16 +108,16 @@ as syntax objects:
(syntax-e #'(+ 1 2)) (syntax-e #'(+ 1 2))
] ]
The @scheme[syntax-e] function always leaves syntax-object wrappers The @racket[syntax-e] function always leaves syntax-object wrappers
around sub-forms that are represented via symbols, numbers, and other around sub-forms that are represented via symbols, numbers, and other
literal values. The only time it unwraps extra sub-forms is when literal values. The only time it unwraps extra sub-forms is when
unwrapping a pair, in which case the @scheme[cdr] of the pair may be unwrapping a pair, in which case the @racket[cdr] of the pair may be
recursively unwrapped, depending on how the syntax object was recursively unwrapped, depending on how the syntax object was
constructed. constructed.
The opposite of @scheme[syntax->datum] is, of course, The opposite of @racket[syntax->datum] is, of course,
@scheme[datum->syntax]. In addition to a datum like @scheme['(+ 1 @racket[datum->syntax]. In addition to a datum like @racket['(+ 1
2)], @scheme[datum->syntax] needs an existing syntax object to donate 2)], @racket[datum->syntax] needs an existing syntax object to donate
its lexical context, and optionally another syntax object to donate its lexical context, and optionally another syntax object to donate
its source location: its source location:
@ -127,44 +127,44 @@ its source location:
#'srcloc) #'srcloc)
] ]
In the above example, the lexical context of @scheme[#'lex] is used In the above example, the lexical context of @racket[#'lex] is used
for the new syntax object, while the source location of for the new syntax object, while the source location of
@scheme[#'srcloc] is used. @racket[#'srcloc] is used.
When the second (i.e., the ``datum'') argument to When the second (i.e., the ``datum'') argument to
@scheme[datum->syntax] includes syntax objects, those syntax objects @racket[datum->syntax] includes syntax objects, those syntax objects
are preserved intact in the result. That is, deconstructing the result are preserved intact in the result. That is, deconstructing the result
with @scheme[syntax-e] eventually produces the syntax objects that with @racket[syntax-e] eventually produces the syntax objects that
were given to @scheme[datum->syntax]. were given to @racket[datum->syntax].
@; ---------------------------------------- @; ----------------------------------------
@section[#:tag "syntax-case"]{Mixing Patterns and Expressions: @scheme[syntax-case]} @section[#:tag "syntax-case"]{Mixing Patterns and Expressions: @racket[syntax-case]}
The procedure generated by @scheme[syntax-rules] internally uses The procedure generated by @racket[syntax-rules] internally uses
@scheme[syntax-e] to deconstruct the given syntax object, and it uses @racket[syntax-e] to deconstruct the given syntax object, and it uses
@scheme[datum->syntax] to construct the result. The @racket[datum->syntax] to construct the result. The
@scheme[syntax-rules] form doesn't provide a way to escape from @racket[syntax-rules] form doesn't provide a way to escape from
pattern-matching and template-construction mode into an arbitrary pattern-matching and template-construction mode into an arbitrary
Scheme expression. Racket expression.
The @scheme[syntax-case] form lets you mix pattern matching, template The @racket[syntax-case] form lets you mix pattern matching, template
construction, and arbitrary expressions: construction, and arbitrary expressions:
@specform[(syntax-case stx-expr (literal-id ...) @specform[(syntax-case stx-expr (literal-id ...)
[pattern expr] [pattern expr]
...)] ...)]
Unlike @scheme[syntax-rules], the @scheme[syntax-case] form does not Unlike @racket[syntax-rules], the @racket[syntax-case] form does not
produce a procedure. Instead, it starts with a @scheme[_stx-expr] produce a procedure. Instead, it starts with a @racket[_stx-expr]
expression that determines the syntax object to match against the expression that determines the syntax object to match against the
@scheme[_pattern]s. Also, each @scheme[syntax-case] clause has a @racket[_pattern]s. Also, each @racket[syntax-case] clause has a
@scheme[_pattern] and @scheme[_expr], instead of a @scheme[_pattern] @racket[_pattern] and @racket[_expr], instead of a @racket[_pattern]
and @scheme[_template]. Within an @scheme[_expr], the @scheme[syntax] and @racket[_template]. Within an @racket[_expr], the @racket[syntax]
form---usually abbreviated with @litchar{#'}---shifts into form---usually abbreviated with @litchar{#'}---shifts into
template-construction mode; if the @scheme[_expr] of a clause starts template-construction mode; if the @racket[_expr] of a clause starts
with @litchar{#'}, then we have something like a @scheme[syntax-rules] with @litchar{#'}, then we have something like a @racket[syntax-rules]
form: form:
@interaction[ @interaction[
@ -173,10 +173,10 @@ form:
[(op n1 n2) #'(- n1 n2)])) [(op n1 n2) #'(- n1 n2)]))
] ]
We could write the @scheme[swap] macro using @scheme[syntax-case] We could write the @racket[swap] macro using @racket[syntax-case]
instead of @scheme[define-syntax-rule] or @scheme[syntax-rules]: instead of @racket[define-syntax-rule] or @racket[syntax-rules]:
@schemeblock[ @racketblock[
(define-syntax swap (define-syntax swap
(lambda (stx) (lambda (stx)
(syntax-case stx () (syntax-case stx ()
@ -185,15 +185,15 @@ instead of @scheme[define-syntax-rule] or @scheme[syntax-rules]:
(set! y tmp))]))) (set! y tmp))])))
] ]
One advantage of using @scheme[syntax-case] is that we can provide One advantage of using @racket[syntax-case] is that we can provide
better error reporting for @scheme[swap]. For example, with the better error reporting for @racket[swap]. For example, with the
@scheme[define-syntax-rule] definition of @scheme[swap], then @racket[define-syntax-rule] definition of @racket[swap], then
@scheme[(swap x 2)] produces a syntax error in terms of @scheme[set!], @racket[(swap x 2)] produces a syntax error in terms of @racket[set!],
because @scheme[2] is not an identifier. We can refine our because @racket[2] is not an identifier. We can refine our
@scheme[syntax-case] implementation of @scheme[swap] to explicitly @racket[syntax-case] implementation of @racket[swap] to explicitly
check the sub-forms: check the sub-forms:
@schemeblock[ @racketblock[
(define-syntax swap (define-syntax swap
(lambda (stx) (lambda (stx)
(syntax-case stx () (syntax-case stx ()
@ -211,29 +211,29 @@ check the sub-forms:
#'x)))]))) #'x)))])))
] ]
With this definition, @scheme[(swap x 2)] provides a syntax error With this definition, @racket[(swap x 2)] provides a syntax error
originating from @scheme[swap] instead of @scheme[set!]. originating from @racket[swap] instead of @racket[set!].
In the above definition of @scheme[swap], @scheme[#'x] and In the above definition of @racket[swap], @racket[#'x] and
@scheme[#'y] are templates, even though they are not used as the @racket[#'y] are templates, even though they are not used as the
result of the macro transformer. This example illustrates how result of the macro transformer. This example illustrates how
templates can be used to access pieces of the input syntax, in this templates can be used to access pieces of the input syntax, in this
case for checking the form of the pieces. Also, the match for case for checking the form of the pieces. Also, the match for
@scheme[#'x] or @scheme[#'y] is used in the call to @racket[#'x] or @racket[#'y] is used in the call to
@scheme[raise-syntax-error], so that the syntax-error message can @racket[raise-syntax-error], so that the syntax-error message can
point directly to the source location of the non-identifier. point directly to the source location of the non-identifier.
@; ---------------------------------------- @; ----------------------------------------
@section[#:tag "with-syntax"]{@scheme[with-syntax] and @scheme[generate-temporaries]} @section[#:tag "with-syntax"]{@racket[with-syntax] and @racket[generate-temporaries]}
Since @scheme[syntax-case] lets us compute with arbitrary Scheme Since @racket[syntax-case] lets us compute with arbitrary Racket
expression, we can more simply solve a problem that we had in expression, we can more simply solve a problem that we had in
writing @scheme[define-for-cbr] (see writing @racket[define-for-cbr] (see
@secref["pattern-macro-example"]), where we needed to generate a @secref["pattern-macro-example"]), where we needed to generate a
set of names based on a sequence @scheme[id ...]: set of names based on a sequence @racket[id ...]:
@schemeblock[ @racketblock[
(define-syntax (define-for-cbr stx) (define-syntax (define-for-cbr stx)
(syntax-case stx () (syntax-case stx ()
[(_ do-f (id ...) body) [(_ do-f (id ...) body)
@ -243,17 +243,17 @@ set of names based on a sequence @scheme[id ...]:
body) ....])) body) ....]))
] ]
@margin-note{This example uses @scheme[(define-syntax (_id _arg) _body ...+)], @margin-note{This example uses @racket[(define-syntax (_id _arg) _body ...+)],
which is equivalent to @scheme[(define-syntax _id (lambda (_arg) _body ...+))].} which is equivalent to @racket[(define-syntax _id (lambda (_arg) _body ...+))].}
In place of the @scheme[....]s above, we need to bind @scheme[get In place of the @racket[....]s above, we need to bind @racket[get
...] and @scheme[put ...] to lists of generated identifiers. We ...] and @racket[put ...] to lists of generated identifiers. We
cannot use @scheme[let] to bind @scheme[get] and @scheme[put], cannot use @racket[let] to bind @racket[get] and @racket[put],
because we need bindings that count as pattern variables, instead because we need bindings that count as pattern variables, instead
of normal local variables. The @scheme[with-syntax] form lets us of normal local variables. The @racket[with-syntax] form lets us
bind pattern variables: bind pattern variables:
@schemeblock[ @racketblock[
(define-syntax (define-for-cbr stx) (define-syntax (define-for-cbr stx)
(syntax-case stx () (syntax-case stx ()
[(_ do-f (id ...) body) [(_ do-f (id ...) body)
@ -264,14 +264,14 @@ bind pattern variables:
body))])) body))]))
] ]
Now we need an expression in place of @scheme[....] that Now we need an expression in place of @racket[....] that
generates as many identifiers as there are @scheme[id] matches in generates as many identifiers as there are @racket[id] matches in
the original pattern. Since this is a common task, Scheme the original pattern. Since this is a common task, Racket
provides a helper function, @scheme[generate-temporaries], that provides a helper function, @racket[generate-temporaries], that
takes a sequece of identifiers and returns a sequence of takes a sequece of identifiers and returns a sequence of
generated identifiers: generated identifiers:
@schemeblock[ @racketblock[
(define-syntax (define-for-cbr stx) (define-syntax (define-for-cbr stx)
(syntax-case stx () (syntax-case stx ()
[(_ do-f (id ...) body) [(_ do-f (id ...) body)
@ -286,9 +286,9 @@ This way of generating identifiers is normally easier to think
about than tricking the macro expander into generating names with about than tricking the macro expander into generating names with
purely pattern-based macros. purely pattern-based macros.
In general, the right-hand side of a @scheme[with-syntax] In general, the right-hand side of a @racket[with-syntax]
binding is a pattern, just like in @scheme[syntax-case]. In fact, binding is a pattern, just like in @racket[syntax-case]. In fact,
a @scheme[with-syntax] form is just a @scheme[syntax-case] form a @racket[with-syntax] form is just a @racket[syntax-case] form
turned partially inside-out. turned partially inside-out.
@; ---------------------------------------- @; ----------------------------------------
@ -297,13 +297,13 @@ turned partially inside-out.
As sets of macros get more complicated, you might want to write As sets of macros get more complicated, you might want to write
your own helper functions, like your own helper functions, like
@scheme[generate-temporaries]. For example, to provide good @racket[generate-temporaries]. For example, to provide good
syntax-error messsage, @scheme[swap], @scheme[rotate], and syntax-error messsage, @racket[swap], @racket[rotate], and
@scheme[define-cbr] all should check that certain sub-forms in @racket[define-cbr] all should check that certain sub-forms in
the source form are identifiers. We could use a the source form are identifiers. We could use a
@scheme[check-ids] to perform this checking everywhere: @racket[check-ids] to perform this checking everywhere:
@schemeblock/eval[ @racketblock/eval[
#:eval check-eval #:eval check-eval
(define-syntax (swap stx) (define-syntax (swap stx)
(syntax-case stx () (syntax-case stx ()
@ -321,11 +321,11 @@ the source form are identifiers. We could use a
#'(shift-to (c ... a) (a c ...)))])) #'(shift-to (c ... a) (a c ...)))]))
] ]
The @scheme[check-ids] function can use the @scheme[syntax->list] The @racket[check-ids] function can use the @racket[syntax->list]
function to convert a syntax-object wrapping a list into a list function to convert a syntax-object wrapping a list into a list
of syntax objects: of syntax objects:
@schemeblock[ @racketblock[
(define (check-ids stx forms) (define (check-ids stx forms)
(for-each (for-each
(lambda (form) (lambda (form)
@ -337,7 +337,7 @@ of syntax objects:
(syntax->list forms))) (syntax->list forms)))
] ]
If you define @scheme[swap] and @scheme[check-ids] in this way, If you define @racket[swap] and @racket[check-ids] in this way,
however, it doesn't work: however, it doesn't work:
@interaction[ @interaction[
@ -345,18 +345,18 @@ however, it doesn't work:
(let ([a 1] [b 2]) (swap a b)) (let ([a 1] [b 2]) (swap a b))
] ]
The problem is that @scheme[check-ids] is defined as a run-time The problem is that @racket[check-ids] is defined as a run-time
expression, but @scheme[swap] is trying to use it at compile time. In expression, but @racket[swap] is trying to use it at compile time. In
interactive mode, compile time and run time are interleaved, but they interactive mode, compile time and run time are interleaved, but they
are not interleaved within the body of a module, and they are not are not interleaved within the body of a module, and they are not
interleaved or across modules that are compiled ahead-of-time. To help interleaved or across modules that are compiled ahead-of-time. To help
make all of these modes treat code consistently, Scheme separates the make all of these modes treat code consistently, Racket separates the
binding spaces for different phases. binding spaces for different phases.
To define a @scheme[check-ids] function that can be referenced at To define a @racket[check-ids] function that can be referenced at
compile time, use @scheme[define-for-syntax]: compile time, use @racket[define-for-syntax]:
@schemeblock/eval[ @racketblock/eval[
#:eval check-eval #:eval check-eval
(define-for-syntax (check-ids stx forms) (define-for-syntax (check-ids stx forms)
(for-each (for-each
@ -369,7 +369,7 @@ compile time, use @scheme[define-for-syntax]:
(syntax->list forms))) (syntax->list forms)))
] ]
With this for-syntax definition, then @scheme[swap] works: With this for-syntax definition, then @racket[swap] works:
@interaction[ @interaction[
#:eval check-eval #:eval check-eval
@ -380,11 +380,11 @@ With this for-syntax definition, then @scheme[swap] works:
When organizing a program into modules, you may want to put helper When organizing a program into modules, you may want to put helper
functions in one module to be used by macros that reside on other functions in one module to be used by macros that reside on other
modules. In that case, you can write the helper function using modules. In that case, you can write the helper function using
@scheme[define]: @racket[define]:
@schememod[#:file @racketmod[#:file
"utils.ss" "utils.ss"
scheme racket
(provide check-ids) (provide check-ids)
@ -400,11 +400,11 @@ scheme
] ]
Then, in the module that implements macros, import the helper function Then, in the module that implements macros, import the helper function
using @scheme[(require (for-syntax "utils.ss"))] instead of using @racket[(require (for-syntax "utils.ss"))] instead of
@scheme[(require "utils.ss")]: @racket[(require "utils.ss")]:
@schememod[ @racketmod[
scheme racket
(require (for-syntax "utils.ss")) (require (for-syntax "utils.ss"))
@ -420,38 +420,38 @@ scheme
Since modules are separately compiled and cannot have circular Since modules are separately compiled and cannot have circular
dependencies, the @filepath["utils.ss"] module's run-time body can be dependencies, the @filepath["utils.ss"] module's run-time body can be
compiled before the compiling the module that implements compiled before the compiling the module that implements
@scheme[swap]. Thus, the run-time definitions in @racket[swap]. Thus, the run-time definitions in
@filepath["utils.ss"] can be used to implement @scheme[swap], as long @filepath["utils.ss"] can be used to implement @racket[swap], as long
as they are explicitly shifted into compile time by @scheme[(require as they are explicitly shifted into compile time by @racket[(require
(for-syntax ....))]. (for-syntax ....))].
The @schememodname[scheme] module provides @scheme[syntax-case], The @racketmodname[racket] module provides @racket[syntax-case],
@scheme[generate-temporaries], @scheme[lambda], @scheme[if], and more @racket[generate-temporaries], @racket[lambda], @racket[if], and more
for use in both the run-time and compile-time phases. That is why we for use in both the run-time and compile-time phases. That is why we
can use @scheme[syntax-case] in the @scheme[mzscheme] @tech{REPL} both can use @racket[syntax-case] in the @exec{racket} @tech{REPL} both
directly and in the right-hand side of a @scheme[define-syntax] directly and in the right-hand side of a @racket[define-syntax]
form. form.
The @schememodname[scheme/base] module, in contrast, exports those The @racketmodname[racket/base] module, in contrast, exports those
bindings only in the run-time phase. If you change the module above bindings only in the run-time phase. If you change the module above
that defines @scheme[swap] so that it uses the that defines @racket[swap] so that it uses the
@schememodname[scheme/base] language instead of @racketmodname[racket/base] language instead of
@schememodname[scheme], then it no longer works. Adding @racketmodname[racket], then it no longer works. Adding
@scheme[(require (for-syntax scheme/base))] imports @racket[(require (for-syntax racket/base))] imports
@scheme[syntax-case] and more into the compile-time phase, so that the @racket[syntax-case] and more into the compile-time phase, so that the
module works again. module works again.
Suppose that @scheme[define-syntax] is used to define a local macro in Suppose that @racket[define-syntax] is used to define a local macro in
the right-hand side of a @scheme[define-syntax] form. In that case, the right-hand side of a @racket[define-syntax] form. In that case,
the right-hand side of the inner @scheme[define-syntax] is in the the right-hand side of the inner @racket[define-syntax] is in the
@deftech{meta-compile phase level}, also known as @deftech{phase level @deftech{meta-compile phase level}, also known as @deftech{phase level
2}. To import @scheme[syntax-case] into that phase level, you would 2}. To import @racket[syntax-case] into that phase level, you would
have to use @scheme[(require (for-syntax (for-syntax scheme/base)))] have to use @racket[(require (for-syntax (for-syntax racket/base)))]
or, equivalently, @scheme[(require (for-meta 2 scheme/base))]. or, equivalently, @racket[(require (for-meta 2 racket/base))].
Negative phase levels also exist. If a macro uses a helper function Negative phase levels also exist. If a macro uses a helper function
that is imported @scheme[for-syntax], and if the helper function that is imported @racket[for-syntax], and if the helper function
returns syntax-object constants generated by @scheme[syntax], then returns syntax-object constants generated by @racket[syntax], then
identifiers in the syntax will need bindings at @deftech{phase level identifiers in the syntax will need bindings at @deftech{phase level
-1}, also known as the @deftech{template phase level}, to have any -1}, also known as the @deftech{template phase level}, to have any
binding at the run-time phase level relative to the module that binding at the run-time phase level relative to the module that

View File

@ -12,7 +12,7 @@ A @deftech{regexp} value encapsulates a pattern that is described by a
string or @tech{byte string}. The regexp matcher tries to match this string or @tech{byte string}. The regexp matcher tries to match this
pattern against (a portion of) another string or byte string, which we pattern against (a portion of) another string or byte string, which we
will call the @deftech{text string}, when you call functions like will call the @deftech{text string}, when you call functions like
@scheme[regexp-match]. The text string is treated as raw text, and @racket[regexp-match]. The text string is treated as raw text, and
not as a pattern. not as a pattern.
@local-table-of-contents[] @local-table-of-contents[]
@ -25,30 +25,30 @@ not as a pattern.
A string or @tech{byte string} can be used directly as a @tech{regexp} A string or @tech{byte string} can be used directly as a @tech{regexp}
pattern, or it can be prefixed with @litchar{#rx} to form a literal pattern, or it can be prefixed with @litchar{#rx} to form a literal
@tech{regexp} value. For example, @scheme[#rx"abc"] is a string-based @tech{regexp} value. For example, @racket[#rx"abc"] is a string-based
@tech{regexp} value, and @scheme[#rx#"abc"] is a @tech{byte @tech{regexp} value, and @racket[#rx#"abc"] is a @tech{byte
string}-based @tech{regexp} value. Alternately, a string or byte string}-based @tech{regexp} value. Alternately, a string or byte
string can be prefixed with @litchar{#px}, as in @scheme[#px"abc"], string can be prefixed with @litchar{#px}, as in @racket[#px"abc"],
for a slightly extended syntax of patterns within the string. for a slightly extended syntax of patterns within the string.
Most of the characters in a @tech{regexp} pattern are meant to match Most of the characters in a @tech{regexp} pattern are meant to match
occurrences of themselves in the @tech{text string}. Thus, the pattern occurrences of themselves in the @tech{text string}. Thus, the pattern
@scheme[#rx"abc"] matches a string that contains the characters @racket[#rx"abc"] matches a string that contains the characters
@litchar{a}, @litchar{b}, and @litchar{c} in succession. Other @litchar{a}, @litchar{b}, and @litchar{c} in succession. Other
characters act as @deftech{metacharacters}, and some character characters act as @deftech{metacharacters}, and some character
sequences act as @deftech{metasequences}. That is, they specify sequences act as @deftech{metasequences}. That is, they specify
something other than their literal selves. For example, in the something other than their literal selves. For example, in the
pattern @scheme[#rx"a.c"], the characters @litchar{a} and @litchar{c} pattern @racket[#rx"a.c"], the characters @litchar{a} and @litchar{c}
stand for themselves, but the @tech{metacharacter} @litchar{.} can stand for themselves, but the @tech{metacharacter} @litchar{.} can
match @emph{any} character. Therefore, the pattern @scheme[#rx"a.c"] match @emph{any} character. Therefore, the pattern @racket[#rx"a.c"]
matches an @litchar{a}, any character, and @litchar{c} in succession. matches an @litchar{a}, any character, and @litchar{c} in succession.
@margin-note{When we want a literal @litchar{\} inside a Scheme string @margin-note{When we want a literal @litchar{\} inside a Racket string
or regexp literal, we must escape it so that it shows up in the string or regexp literal, we must escape it so that it shows up in the string
at all. Scheme strings use @litchar{\} as the escape character, so we at all. Racket strings use @litchar{\} as the escape character, so we
end up with two @litchar{\}s: one Scheme-string @litchar{\} to escape end up with two @litchar{\}s: one Racket-string @litchar{\} to escape
the regexp @litchar{\}, which then escapes the @litchar{.}. Another the regexp @litchar{\}, which then escapes the @litchar{.}. Another
character that would need escaping inside a Scheme string is character that would need escaping inside a Racket string is
@litchar{"}.} @litchar{"}.}
If we needed to match the character @litchar{.} itself, we can escape If we needed to match the character @litchar{.} itself, we can escape
@ -56,19 +56,19 @@ it by precede it with a @litchar{\}. The character sequence
@litchar{\.} is thus a @tech{metasequence}, since it doesn't match @litchar{\.} is thus a @tech{metasequence}, since it doesn't match
itself but rather just @litchar{.}. So, to match @litchar{a}, itself but rather just @litchar{.}. So, to match @litchar{a},
@litchar{.}, and @litchar{c} in succession, we use the regexp pattern @litchar{.}, and @litchar{c} in succession, we use the regexp pattern
@scheme[#rx"a\\.c"]; the double @litchar{\} is an artifact of Scheme @racket[#rx"a\\.c"]; the double @litchar{\} is an artifact of Racket
strings, not the @tech{regexp} pattern itself. strings, not the @tech{regexp} pattern itself.
The @scheme[regexp] function takes a string or byte string and The @racket[regexp] function takes a string or byte string and
produces a @tech{regexp} value. Use @scheme[regexp] when you construct produces a @tech{regexp} value. Use @racket[regexp] when you construct
a pattern to be matched against multiple strings, since a pattern is a pattern to be matched against multiple strings, since a pattern is
compiled to a @tech{regexp} value before it can be used in a match. compiled to a @tech{regexp} value before it can be used in a match.
The @scheme[pregexp] function is like @scheme[regexp], but using the The @racket[pregexp] function is like @racket[regexp], but using the
extended syntax. Regexp values as literals with @litchar{#rx} or extended syntax. Regexp values as literals with @litchar{#rx} or
@litchar{#px} are compiled once and for all when they are read. @litchar{#px} are compiled once and for all when they are read.
The @scheme[regexp-quote] function takes an arbitrary string and The @racket[regexp-quote] function takes an arbitrary string and
returns a string for a pattern that matches exactly the original returns a string for a pattern that matches exactly the original
string. In particular, characters in the input string that could serve string. In particular, characters in the input string that could serve
as regexp metacharacters are escaped with a backslash, so that they as regexp metacharacters are escaped with a backslash, so that they
@ -79,7 +79,7 @@ safely match only themselves.
(regexp-quote "list?") (regexp-quote "list?")
] ]
The @scheme[regexp-quote] function is useful when building a composite The @racket[regexp-quote] function is useful when building a composite
@tech{regexp} from a mix of @tech{regexp} strings and verbatim strings. @tech{regexp} from a mix of @tech{regexp} strings and verbatim strings.
@ -87,9 +87,9 @@ The @scheme[regexp-quote] function is useful when building a composite
@section[#:tag "regexp-match"]{Matching Regexp Patterns} @section[#:tag "regexp-match"]{Matching Regexp Patterns}
The @scheme[regexp-match-positions] function takes a @tech{regexp} The @racket[regexp-match-positions] function takes a @tech{regexp}
pattern and a @tech{text string}, and it returns a match if the regexp pattern and a @tech{text string}, and it returns a match if the regexp
matches (some part of) the @tech{text string}, or @scheme[#f] if the regexp matches (some part of) the @tech{text string}, or @racket[#f] if the regexp
did not match the string. A successful match produces a list of did not match the string. A successful match produces a list of
@deftech{index pairs}. @deftech{index pairs}.
@ -98,22 +98,22 @@ did not match the string. A successful match produces a list of
(regexp-match-positions #rx"needle" "hay needle stack") (regexp-match-positions #rx"needle" "hay needle stack")
] ]
In the second example, the integers @scheme[4] and @scheme[10] In the second example, the integers @racket[4] and @racket[10]
identify the substring that was matched. The @scheme[4] is the identify the substring that was matched. The @racket[4] is the
starting (inclusive) index, and @scheme[10] the ending (exclusive) starting (inclusive) index, and @racket[10] the ending (exclusive)
index of the matching substring: index of the matching substring:
@interaction[ @interaction[
(substring "hay needle stack" 4 10) (substring "hay needle stack" 4 10)
] ]
In this first example, @scheme[regexp-match-positions]'s return list In this first example, @racket[regexp-match-positions]'s return list
contains only one index pair, and that pair represents the entire contains only one index pair, and that pair represents the entire
substring matched by the regexp. When we discuss @tech{subpatterns} substring matched by the regexp. When we discuss @tech{subpatterns}
later, we will see how a single match operation can yield a list of later, we will see how a single match operation can yield a list of
@tech{submatch}es. @tech{submatch}es.
The @scheme[regexp-match-positions] function takes optional third and The @racket[regexp-match-positions] function takes optional third and
fourth arguments that specify the indices of the @tech{text string} within fourth arguments that specify the indices of the @tech{text string} within
which the matching should take place. which the matching should take place.
@ -127,8 +127,8 @@ which the matching should take place.
Note that the returned indices are still reckoned relative to the full Note that the returned indices are still reckoned relative to the full
@tech{text string}. @tech{text string}.
The @scheme[regexp-match] function is like The @racket[regexp-match] function is like
@scheme[regexp-match-positions], but instead of returning index pairs, @racket[regexp-match-positions], but instead of returning index pairs,
it returns the matching substrings: it returns the matching substrings:
@interaction[ @interaction[
@ -136,7 +136,7 @@ it returns the matching substrings:
(regexp-match #rx"needle" "hay needle stack") (regexp-match #rx"needle" "hay needle stack")
] ]
When @scheme[regexp-match] is used with byte-string regexp, the result When @racket[regexp-match] is used with byte-string regexp, the result
is a matching byte substring: is a matching byte substring:
@interaction[ @interaction[
@ -153,7 +153,7 @@ is a matching byte substring:
avoids UTF-8 encodings.} avoids UTF-8 encodings.}
If you have data that is in a port, there's no need to first read it If you have data that is in a port, there's no need to first read it
into a string. Functions like @scheme[regexp-match] can match on the into a string. Functions like @racket[regexp-match] can match on the
port directly: port directly:
@interaction[ @interaction[
@ -163,8 +163,8 @@ port directly:
(regexp-match #rx#"needle" i) (regexp-match #rx#"needle" i)
] ]
The @scheme[regexp-match?] function is like The @racket[regexp-match?] function is like
@scheme[regexp-match-positions], but simply returns a boolean @racket[regexp-match-positions], but simply returns a boolean
indicating whether the match succeeded: indicating whether the match succeeded:
@interaction[ @interaction[
@ -172,7 +172,7 @@ indicating whether the match succeeded:
(regexp-match? #rx"needle" "hay needle stack") (regexp-match? #rx"needle" "hay needle stack")
] ]
The @scheme[regexp-split] function takes two arguments, a The @racket[regexp-split] function takes two arguments, a
@tech{regexp} pattern and a text string, and it returns a list of @tech{regexp} pattern and a text string, and it returns a list of
substrings of the text string; the pattern identifies the delimiter substrings of the text string; the pattern identifies the delimiter
separating the substrings. separating the substrings.
@ -190,32 +190,32 @@ single-character substrings is returned.
] ]
Thus, to identify one-or-more spaces as the delimiter, take care to Thus, to identify one-or-more spaces as the delimiter, take care to
use the regexp @scheme[#rx"\u20+"], not @scheme[#rx"\u20*"]. use the regexp @racket[#rx"\u20+"], not @racket[#rx"\u20*"].
@interaction[ @interaction[
(regexp-split #rx" +" "split pea soup") (regexp-split #rx" +" "split pea soup")
(regexp-split #rx" *" "split pea soup") (regexp-split #rx" *" "split pea soup")
] ]
The @scheme[regexp-replace] function replaces the matched portion of The @racket[regexp-replace] function replaces the matched portion of
the text string by another string. The first argument is the pattern, the text string by another string. The first argument is the pattern,
the second the text string, and the third is either the string to be the second the text string, and the third is either the string to be
inserted or a procedure to convert matches to the insert string. inserted or a procedure to convert matches to the insert string.
@interaction[ @interaction[
(regexp-replace #rx"te" "liberte" "ty") (regexp-replace #rx"te" "liberte" "ty")
(regexp-replace #rx"." "scheme" string-upcase) (regexp-replace #rx"." "racket" string-upcase)
] ]
If the pattern doesn't occur in the text string, the returned string If the pattern doesn't occur in the text string, the returned string
is identical to the text string. is identical to the text string.
The @scheme[regexp-replace*] function replaces @emph{all} matches in The @racket[regexp-replace*] function replaces @emph{all} matches in
the text string by the insert string: the text string by the insert string:
@interaction[ @interaction[
(regexp-replace* #rx"te" "liberte egalite fraternite" "ty") (regexp-replace* #rx"te" "liberte egalite fraternite" "ty")
(regexp-replace* #rx"[ds]" "drscheme" string-upcase) (regexp-replace* #rx"[ds]" "drracket" string-upcase)
] ]
@; ---------------------------------------- @; ----------------------------------------
@ -285,20 +285,20 @@ A @deftech{character class} matches any one character from a set of
characters. A typical format for this is the @deftech{bracketed characters. A typical format for this is the @deftech{bracketed
character class} @litchar{[}...@litchar{]}, which matches any one character class} @litchar{[}...@litchar{]}, which matches any one
character from the non-empty sequence of characters enclosed within character from the non-empty sequence of characters enclosed within
the brackets. Thus, @scheme[#rx"p[aeiou]t"] matches @litchar{pat}, the brackets. Thus, @racket[#rx"p[aeiou]t"] matches @litchar{pat},
@litchar{pet}, @litchar{pit}, @litchar{pot}, @litchar{put}, and @litchar{pet}, @litchar{pit}, @litchar{pot}, @litchar{put}, and
nothing else. nothing else.
Inside the brackets, a @litchar{-} between two characters specifies Inside the brackets, a @litchar{-} between two characters specifies
the Unicode range between the characters. For example, the Unicode range between the characters. For example,
@scheme[#rx"ta[b-dgn-p]"] matches @litchar{tab}, @litchar{tac}, @racket[#rx"ta[b-dgn-p]"] matches @litchar{tab}, @litchar{tac},
@litchar{tad}, @litchar{tag}, @litchar{tan}, @litchar{tao}, and @litchar{tad}, @litchar{tag}, @litchar{tan}, @litchar{tao}, and
@litchar{tap}. @litchar{tap}.
An initial @litchar{^} after the left bracket inverts the set An initial @litchar{^} after the left bracket inverts the set
specified by the rest of the contents; i.e., it specifies the set of specified by the rest of the contents; i.e., it specifies the set of
characters @emph{other than} those identified in the brackets. For characters @emph{other than} those identified in the brackets. For
example, @scheme[#rx"do[^g]"] matches all three-character sequences example, @racket[#rx"do[^g]"] matches all three-character sequences
starting with @litchar{do} except @litchar{dog}. starting with @litchar{do} except @litchar{dog}.
Note that the @tech{metacharacter} @litchar{^} inside brackets means Note that the @tech{metacharacter} @litchar{^} inside brackets means
@ -314,12 +314,12 @@ Bracketed character classes cannot contain other bracketed character
classes (although they contain certain other types of character classes (although they contain certain other types of character
classes; see below). Thus, a @litchar{[} inside a bracketed character classes; see below). Thus, a @litchar{[} inside a bracketed character
class doesn't have to be a metacharacter; it can stand for itself. class doesn't have to be a metacharacter; it can stand for itself.
For example, @scheme[#rx"[a[b]"] matches @litchar{a}, @litchar{[}, and For example, @racket[#rx"[a[b]"] matches @litchar{a}, @litchar{[}, and
@litchar{b}. @litchar{b}.
Furthermore, since empty bracketed character classes are disallowed, a Furthermore, since empty bracketed character classes are disallowed, a
@litchar{]} immediately occurring after the opening left bracket also @litchar{]} immediately occurring after the opening left bracket also
doesn't need to be a metacharacter. For example, @scheme[#rx"[]ab]"] doesn't need to be a metacharacter. For example, @racket[#rx"[]ab]"]
matches @litchar{]}, @litchar{a}, and @litchar{b}. matches @litchar{]}, @litchar{a}, and @litchar{b}.
@subsection{Some Frequently Used Character Classes} @subsection{Some Frequently Used Character Classes}
@ -333,7 +333,7 @@ bracketed expressions: @litchar{\d} matches a digit
@margin-note{Following regexp custom, we identify ``word'' characters @margin-note{Following regexp custom, we identify ``word'' characters
as @litchar{[A-Za-z0-9_]}, although these are too restrictive for what as @litchar{[A-Za-z0-9_]}, although these are too restrictive for what
a Schemer might consider a ``word.''} a Racketr might consider a ``word.''}
The upper-case versions of these metasequences stand for the The upper-case versions of these metasequences stand for the
inversions of the corresponding character classes: @litchar{\D} inversions of the corresponding character classes: @litchar{\D}
@ -341,7 +341,7 @@ matches a non-digit, @litchar{\S} a non-whitespace character, and
@litchar{\W} a non-``word'' character. @litchar{\W} a non-``word'' character.
Remember to include a double backslash when putting these Remember to include a double backslash when putting these
metasequences in a Scheme string: metasequences in a Racket string:
@interaction[ @interaction[
(regexp-match #px"\\d\\d" (regexp-match #px"\\d\\d"
@ -349,7 +349,7 @@ metasequences in a Scheme string:
] ]
These character classes can be used inside a bracketed expression. For These character classes can be used inside a bracketed expression. For
example, @scheme[#px"[a-z\\d]"] matches a lower-case letter or a example, @racket[#px"[a-z\\d]"] matches a lower-case letter or a
digit. digit.
@subsection{POSIX character classes} @subsection{POSIX character classes}
@ -389,7 +389,7 @@ supported are
] ]
For example, the @scheme[#px"[[:alpha:]_]"] matches a letter or For example, the @racket[#px"[[:alpha:]_]"] matches a letter or
underscore. underscore.
@interaction[ @interaction[
@ -516,7 +516,7 @@ it is the last submatch that is returned.
It is also possible for a quantified subpattern to fail to match, even It is also possible for a quantified subpattern to fail to match, even
if the overall pattern matches. In such cases, the failing submatch if the overall pattern matches. In such cases, the failing submatch
is represented by @scheme[#f] is represented by @racket[#f]
@interaction[ @interaction[
(define date-re (define date-re
@ -531,7 +531,7 @@ is represented by @scheme[#f]
@subsection{Backreferences} @subsection{Backreferences}
@tech{Submatch}es can be used in the insert string argument of the @tech{Submatch}es can be used in the insert string argument of the
procedures @scheme[regexp-replace] and @scheme[regexp-replace*]. The procedures @racket[regexp-replace] and @racket[regexp-replace*]. The
insert string can use @litchar{\}@math{n} as a @deftech{backreference} insert string can use @litchar{\}@math{n} as a @deftech{backreference}
to refer back to the @math{n}th submatch, which is the substring to refer back to the @math{n}th submatch, which is the substring
that matched the @math{n}th subpattern. A @litchar{\0} refers to the that matched the @math{n}th subpattern. A @litchar{\0} refers to the
@ -612,11 +612,11 @@ In the following example, a non-capturing cluster eliminates the
cluster identifies the basename. cluster identifies the basename.
@margin-note{But don't parse paths with regexps. Use functions like @margin-note{But don't parse paths with regexps. Use functions like
@scheme[split-path], instead.} @racket[split-path], instead.}
@interaction[ @interaction[
(regexp-match #rx"^(?:[a-z]*/)*([a-z]+)$" (regexp-match #rx"^(?:[a-z]*/)*([a-z]+)$"
"/usr/local/bin/mzscheme") "/usr/local/bin/racket")
] ]
@subsection[#:tag "regexp-cloister"]{Cloisters} @subsection[#:tag "regexp-cloister"]{Cloisters}
@ -734,7 +734,7 @@ Consider
The regexp consists of two subregexps: @litchar{a*} followed by The regexp consists of two subregexps: @litchar{a*} followed by
@litchar{a}. The subregexp @litchar{a*} cannot be allowed to match @litchar{a}. The subregexp @litchar{a*} cannot be allowed to match
all four @litchar{a}'s in the text string @scheme[aaaa], even though all four @litchar{a}'s in the text string @racket[aaaa], even though
@litchar{*} is a greedy quantifier. It may match only the first @litchar{*} is a greedy quantifier. It may match only the first
three, leaving the last one for the second subregexp. This ensures three, leaving the last one for the second subregexp. This ensures
that the full regexp matches successfully. that the full regexp matches successfully.
@ -800,7 +800,7 @@ its subpattern @emph{could} match.
"i left my grey socks at the greyhound") "i left my grey socks at the greyhound")
] ]
The regexp @scheme[#rx"grey(?=hound)"] matches @litchar{grey}, but The regexp @racket[#rx"grey(?=hound)"] matches @litchar{grey}, but
@emph{only} if it is followed by @litchar{hound}. Thus, the first @emph{only} if it is followed by @litchar{hound}. Thus, the first
@litchar{grey} in the text string is not matched. @litchar{grey} in the text string is not matched.
@ -812,7 +812,7 @@ subpattern @emph{could not} possibly match.
"the gray greyhound ate the grey socks") "the gray greyhound ate the grey socks")
] ]
The regexp @scheme[#rx"grey(?!hound)"] matches @litchar{grey}, but The regexp @racket[#rx"grey(?!hound)"] matches @litchar{grey}, but
only if it is @emph{not} followed by @litchar{hound}. Thus the only if it is @emph{not} followed by @litchar{hound}. Thus the
@litchar{grey} just before @litchar{socks} is matched. @litchar{grey} just before @litchar{socks} is matched.
@ -827,7 +827,7 @@ the text string.
"the hound in the picture is not a greyhound") "the hound in the picture is not a greyhound")
] ]
The regexp @scheme[#rx"(?<=grey)hound"] matches @litchar{hound}, but The regexp @racket[#rx"(?<=grey)hound"] matches @litchar{hound}, but
only if it is preceded by @litchar{grey}. only if it is preceded by @litchar{grey}.
Negative lookbehind with @litchar{?<!} checks that its subpattern Negative lookbehind with @litchar{?<!} checks that its subpattern
@ -838,7 +838,7 @@ could not possibly match immediately to the left.
"the greyhound in the picture is not a hound") "the greyhound in the picture is not a hound")
] ]
The regexp @scheme[#rx"(?<!grey)hound"] matches @litchar{hound}, but The regexp @racket[#rx"(?<!grey)hound"] matches @litchar{hound}, but
only if it is @emph{not} preceded by @litchar{grey}. only if it is @emph{not} preceded by @litchar{grey}.
Lookaheads and lookbehinds can be convenient when they Lookaheads and lookbehinds can be convenient when they
@ -856,7 +856,7 @@ this chapter. The problem is to fashion a regexp that will match any
and only IP addresses or @emph{dotted quads}: four numbers separated and only IP addresses or @emph{dotted quads}: four numbers separated
by three dots, with each number between 0 and 255. by three dots, with each number between 0 and 255.
First, we define a subregexp @scheme[n0-255] that matches 0 through First, we define a subregexp @racket[n0-255] that matches 0 through
255: 255:
@interaction[ @interaction[
@ -872,7 +872,7 @@ First, we define a subregexp @scheme[n0-255] that matches 0 through
")")) ")"))
] ]
@margin-note{Note that @scheme[n0-255] lists prefixes as preferred @margin-note{Note that @racket[n0-255] lists prefixes as preferred
alternates, which is something we cautioned against in alternates, which is something we cautioned against in
@secref["regexp-alternation"]. However, since we intend to anchor @secref["regexp-alternation"]. However, since we intend to anchor
this subregexp explicitly to force an overall match, the order of the this subregexp explicitly to force an overall match, the order of the
@ -886,7 +886,7 @@ must be excluded. So we fashion alternates to get 000
through 199, then 200 through 249, and finally 250 through 199, then 200 through 249, and finally 250
through 255. through 255.
An IP-address is a string that consists of four @scheme[n0-255]s with An IP-address is a string that consists of four @racket[n0-255]s with
three dots separating them. three dots separating them.
@interaction[ @interaction[
@ -894,10 +894,10 @@ three dots separating them.
(define ip-re1 (define ip-re1
(string-append (string-append
"^" (code:comment @#,t{nothing before}) "^" (code:comment @#,t{nothing before})
n0-255 (code:comment @#,t{the first @scheme[n0-255],}) n0-255 (code:comment @#,t{the first @racket[n0-255],})
"(?:" (code:comment @#,t{then the subpattern of}) "(?:" (code:comment @#,t{then the subpattern of})
"\\." (code:comment @#,t{a dot followed by}) "\\." (code:comment @#,t{a dot followed by})
n0-255 (code:comment @#,t{an @scheme[n0-255],}) n0-255 (code:comment @#,t{an @racket[n0-255],})
")" (code:comment @#,t{which is}) ")" (code:comment @#,t{which is})
"{3}" (code:comment @#,t{repeated exactly 3 times}) "{3}" (code:comment @#,t{repeated exactly 3 times})
"$" (code:comment @#,t{with nothing following}) "$" (code:comment @#,t{with nothing following})
@ -920,7 +920,7 @@ which is fine, except that we also have
] ]
All-zero sequences are not valid IP addresses! Lookahead to the All-zero sequences are not valid IP addresses! Lookahead to the
rescue. Before starting to match @scheme[ip-re1], we look ahead to rescue. Before starting to match @racket[ip-re1], we look ahead to
ensure we don't have all zeros. We could use positive lookahead to ensure we don't have all zeros. We could use positive lookahead to
ensure there @emph{is} a digit other than zero. ensure there @emph{is} a digit other than zero.
@ -946,7 +946,7 @@ composed of @emph{only} zeros and dots.
ip-re1))) ip-re1)))
] ]
The regexp @scheme[ip-re] will match all and only valid IP addresses. The regexp @racket[ip-re] will match all and only valid IP addresses.
@interaction[ @interaction[
#:eval ex-eval #:eval ex-eval

View File

@ -1,142 +1,141 @@
#lang scribble/doc #lang scribble/doc
@(require scribble/manual @(require scribble/manual
"guide-utils.ss" "guide-utils.ss"
(for-syntax scheme/pretty)) (for-syntax racket/pretty))
@title[#:tag "running" #:style 'toc]{Running and Creating Executables} @title[#:tag "running" #:style 'toc]{Running and Creating Executables}
While developing programs, many PLT Scheme programmers use the While developing programs, many Racket programmers use the
@seclink[#:doc '(lib "scribblings/drscheme/drscheme.scrbl") @seclink[#:doc '(lib "scribblings/drscheme/drscheme.scrbl")
"top"]{DrScheme} programming environment. To run a program without the "top"]{DrRacket} programming environment. To run a program without the
development environment, use @exec{mzscheme} (for console-based development environment, use @exec{racket} (for console-based
programs) or @exec{mred} (for GUI program). This chapter mainly programs) or @exec{gracket} (for GUI programs). This chapter mainly
explains how to run @exec{mzscheme} and @exec{mred}. explains how to run @exec{racket} and @exec{gracket}.
@local-table-of-contents[] @local-table-of-contents[]
@; ---------------------------------------------------------------------- @; ----------------------------------------------------------------------
@section[#:tag "mzscheme"]{Running @exec{mzscheme} and @exec{mred}} @section[#:tag "racket"]{Running @exec{racket} and @exec{gracket}}
Depending on command-line arguments, @exec{mzscheme} or @exec{mred} Depending on command-line arguments, @exec{racket} or @exec{gracket}
runs in @seclink["start-interactive-mode"]{interactive mode}, runs in @seclink["start-interactive-mode"]{interactive mode},
@seclink["start-module-mode"]{module mode}, or @seclink["start-module-mode"]{module mode}, or
@seclink["start-load-mode"]{load mode}. @seclink["start-load-mode"]{load mode}.
@subsection[#:tag "start-interactive-mode"]{Interactive Mode} @subsection[#:tag "start-interactive-mode"]{Interactive Mode}
When @exec{mzscheme} is run with no command-line arguments (other than When @exec{racket} is run with no command-line arguments (other than
confguration options, like @Flag{j}), then it starts a @tech{REPL} confguration options, like @Flag{j}), then it starts a @tech{REPL}
with a @litchar{> } prompt: with a @litchar{> } prompt:
@verbatim[#:indent 2]{ @verbatim[#:indent 2]{
Welcome to MzScheme Welcome to Racket
> >
} }
@margin-note{For information on GNU Readline support, see @margin-note{For information on GNU Readline support, see
@schememodname[readline].} @racketmodname[readline].}
To initialize the @tech{REPL}'s environment, @exec{mzscheme} first To initialize the @tech{REPL}'s environment, @exec{racket} first
requires the @schememodname[scheme/init] module, which provides all of requires the @racketmodname[racket/init] module, which provides all of
@scheme[scheme], and also installs @scheme[pretty-print] for display @racket[racket], and also installs @racket[pretty-print] for display
results. Finally, @exec{mzscheme} loads the file reported by results. Finally, @exec{racket} loads the file reported by
@scheme[(find-system-path 'init-file)], if it exists, before starting @racket[(find-system-path 'init-file)], if it exists, before starting
the @tech{REPL}. the @tech{REPL}.
If any command-line arguments are provided (other than configuration If any command-line arguments are provided (other than configuration
options), add @Flag{i} or @DFlag{repl} to re-enable the options), add @Flag{i} or @DFlag{repl} to re-enable the
@tech{REPL}. For example, @tech{REPL}. For example,
@commandline{mzscheme -e '(display "hi\n")' -i} @commandline{racket -e '(display "hi\n")' -i}
displays ``hi'' on start-up, but still presents a @tech{REPL}. displays ``hi'' on start-up, but still presents a @tech{REPL}.
If module-requiring flags appear before @Flag{i}/@DFlag{repl}, they If module-requiring flags appear before @Flag{i}/@DFlag{repl}, they
cancel the automatic requiring of @schememodname[scheme/init]. This cancel the automatic requiring of @racketmodname[racket/init]. This
behavior can be used to initialize the @tech{REPL}'s environment with behavior can be used to initialize the @tech{REPL}'s environment with
a different language. For example, a different language. For example,
@commandline{mzscheme -l scheme/base -i} @commandline{racket -l racket/base -i}
starts a @tech{REPL} using a much smaller initial language (that loads starts a @tech{REPL} using a much smaller initial language (that loads
much faster). Beware that most modules do not provide the basic syntax much faster). Beware that most modules do not provide the basic syntax
of Scheme, including function-call syntax and @scheme[require]. For of Racket, including function-call syntax and @racket[require]. For
example, example,
@commandline{mzscheme -l scheme/date -i} @commandline{racket -l racket/date -i}
produces a @tech{REPL} that fails for every expression, because produces a @tech{REPL} that fails for every expression, because
@schememodname[scheme/date] provides only a few functions, and not the @racketmodname[racket/date] provides only a few functions, and not the
@scheme[#%top-interaction] and @scheme[#%app] bindings that are needed @racket[#%top-interaction] and @racket[#%app] bindings that are needed
to evaluate top-level function calls in the @tech{REPL}. to evaluate top-level function calls in the @tech{REPL}.
If a module-requiring flag appears after @Flag{i}/@DFlag{repl} instead If a module-requiring flag appears after @Flag{i}/@DFlag{repl} instead
of before it, then the module is required after of before it, then the module is required after
@schememodname[scheme/init] to augment the initial environment. For @racketmodname[racket/init] to augment the initial environment. For
example, example,
@commandline{mzscheme -i -l scheme/date} @commandline{racket -i -l racket/date}
starts a useful @tech{REPL} with @schememodname[scheme/date] available starts a useful @tech{REPL} with @racketmodname[racket/date] available
in addition to the exports of @schememodname[scheme]. in addition to the exports of @racketmodname[racket].
@; ---------------------------------------- @; ----------------------------------------
@subsection[#:tag "start-module-mode"]{Module Mode} @subsection[#:tag "start-module-mode"]{Module Mode}
If a file argument is supplied to @exec{mzscheme} before any If a file argument is supplied to @exec{racket} before any
command-line switch (other than configuration options), then the file command-line switch (other than configuration options), then the file
is required as a module, and (unless @Flag{i}/@DFlag{repl} is is required as a module, and (unless @Flag{i}/@DFlag{repl} is
specified), no @tech{REPL} is started. For example, specified), no @tech{REPL} is started. For example,
@commandline{mzscheme hello.ss} @commandline{racket hello.rkt}
requires the @filepath{hello.ss} module and then exits. Any argument requires the @filepath{hello.rkt} module and then exits. Any argument
after the file name, flag or otherwise, is preserved as a command-line after the file name, flag or otherwise, is preserved as a command-line
argument for use by the required module via argument for use by the required module via
@scheme[current-command-line-arguments]. @racket[current-command-line-arguments].
If command-line flags are used, then the @Flag{u} or If command-line flags are used, then the @Flag{u} or
@DFlag{require-script} flag can be used to explicitly require a file @DFlag{require-script} flag can be used to explicitly require a file
as a module. The @Flag{t} or @DFlag{require} flag is similar, except as a module. The @Flag{t} or @DFlag{require} flag is similar, except
that additional command-line flags are processed by @exec{mzscheme}, that additional command-line flags are processed by @exec{racket},
instead of preserved for the required module. For example, instead of preserved for the required module. For example,
@commandline{mzscheme -t hello.ss -t goodbye.ss} @commandline{racket -t hello.rkt -t goodbye.rkt}
requires the @filepath{hello.ss} module, then requires the requires the @filepath{hello.rkt} module, then requires the
@filepath{goodbye.ss} module, and then exits. @filepath{goodbye.rkt} module, and then exits.
The @Flag{l} or @DFlag{lib} flag is similar to The @Flag{l} or @DFlag{lib} flag is similar to
@Flag{t}/@DFlag{require}, but it requires a module using a @Flag{t}/@DFlag{require}, but it requires a module using a
@scheme[lib] module path instead of a file path. For example, @racket[lib] module path instead of a file path. For example,
@commandline{mzscheme -l compiler} @commandline{racket -l raco}
is the same as running the @exec{mzc} executable with no arguments, is the same as running the @exec{raco} executable with no arguments,
since the @scheme[compiler] module is the main @exec{mzc} since the @racket[raco] module is the executable's main module.
module.
Note that if you wanted to pass command-line flags to Note that if you wanted to pass command-line flags to
@scheme[compiler] above, you would need to protect the flags with a @racket[raco] above, you would need to protect the flags with a
@Flag{-}, so that @exec{mzscheme} doesn't try to parse them itself: @Flag{-}, so that @exec{racket} doesn't try to parse them itself:
@commandline{mzscheme -l compiler -- --make prog.ss} @commandline{racket -l raco -- --help}
@; ---------------------------------------- @; ----------------------------------------
@subsection[#:tag "start-load-mode"]{Load Mode} @subsection[#:tag "start-load-mode"]{Load Mode}
The @Flag{f} or @DFlag{load} flag supports @scheme[load]ing top-level The @Flag{f} or @DFlag{load} flag supports @racket[load]ing top-level
expressions in a file directly, as opposed to expressions within a expressions in a file directly, as opposed to expressions within a
module file. This evaluation is like starting a @tech{REPL} and typing module file. This evaluation is like starting a @tech{REPL} and typing
the expressions directly, except that the results are not printed. the expressions directly, except that the results are not printed.
For example, For example,
@commandline{mzscheme -f hi.ss} @commandline{racket -f hi.rkts}
@scheme[load]s @filepath{hi.ss} and exits. Note that load mode is @racket[load]s @filepath{hi.rkts} and exits. Note that load mode is
generally a bad idea, for the reasons explained in generally a bad idea, for the reasons explained in
@secref["use-module"]; using module mode is typically better. @secref["use-module"]; using module mode is typically better.
@ -144,21 +143,21 @@ The @Flag{e} or @DFlag{eval} flag accepts an expression to evaluate
directly. Unlike file loading, the result of the expression is directly. Unlike file loading, the result of the expression is
printed, as in a @tech{REPL}. For example, printed, as in a @tech{REPL}. For example,
@commandline{mzscheme -e '(current-seconds)'} @commandline{racket -e '(current-seconds)'}
prints the number of seconds since January 1, 1970. prints the number of seconds since January 1, 1970.
For file loading and expression evaluation, the top-level environment For file loading and expression evaluation, the top-level environment
is created in the same way for is created in the same way for
@seclink["start-interactive-mode"]{interactive mode}: @seclink["start-interactive-mode"]{interactive mode}:
@schememodname[scheme/init] is required unless another module is @racketmodname[racket/init] is required unless another module is
specified first. For example, specified first. For example,
@commandline{mzscheme -l scheme/base -e '(current-seconds)'} @commandline{racket -l racket/base -e '(current-seconds)'}
likely runs faster, because it initializes the environment for likely runs faster, because it initializes the environment for
evaluation using the smaller @schememodname[scheme/base] language, evaluation using the smaller @racketmodname[racket/base] language,
instead of @schememodname[scheme/init]. instead of @racketmodname[racket/init].
@; ---------------------------------------------------------------------- @; ----------------------------------------------------------------------

View File

@ -5,13 +5,13 @@
@title[#:tag "scripts"]{Scripts} @title[#:tag "scripts"]{Scripts}
Scheme files can be turned into executable scripts under Unix and Mac Racket files can be turned into executable scripts under Unix and Mac
OS X. Under Windows, a compatibility layer like Cygwin support the OS X. Under Windows, a compatibility layer like Cygwin support the
same kind of scripts, or scripts can be implemented as batch files. same kind of scripts, or scripts can be implemented as batch files.
@section{Unix Scripts} @section{Unix Scripts}
In a Unix environment (including Linux and Mac OS X), a Scheme file can In a Unix environment (including Linux and Mac OS X), a Racket file can
be turned into an executable script using the shell's @as-index{@tt{#!}} be turned into an executable script using the shell's @as-index{@tt{#!}}
convention. The first two characters of the file must be @litchar{#!}; convention. The first two characters of the file must be @litchar{#!};
the next character must be either a space or @litchar{/}, and the the next character must be either a space or @litchar{/}, and the
@ -19,14 +19,14 @@ remainder of the first line must be a command to execute the script. For
some platforms, the total length of the first line is restricted to 32 some platforms, the total length of the first line is restricted to 32
characters, and sometimes the space is required. characters, and sometimes the space is required.
The simplest script format uses an absolute path to a @exec{mzscheme} The simplest script format uses an absolute path to a @exec{racket}
executable followed by a module declaration. For example, if executable followed by a module declaration. For example, if
@exec{mzscheme} is installed in @filepath{/usr/local/bin}, then a file @exec{racket} is installed in @filepath{/usr/local/bin}, then a file
containing the following text acts as a ``hello world'' script: containing the following text acts as a ``hello world'' script:
@verbatim[#:indent 2]{ @verbatim[#:indent 2]{
#! /usr/local/bin/mzscheme #! /usr/local/bin/racket
#lang scheme/base #lang racket/base
"Hello, world!" "Hello, world!"
} }
@ -37,43 +37,43 @@ typing @exec{./hello} at the shell prompt produces the output
The above script works because the operating system automatically puts The above script works because the operating system automatically puts
the path to the script as the argument to the program started by the the path to the script as the argument to the program started by the
@tt{#!} line, and because @exec{mzscheme} treats a single non-flag @tt{#!} line, and because @exec{racket} treats a single non-flag
argument as a file containing a module to run. argument as a file containing a module to run.
Instead of specifying a complete path to the @exec{mzscheme} Instead of specifying a complete path to the @exec{racket}
executable, a popular alternative is to require that @exec{mzscheme} executable, a popular alternative is to require that @exec{racket}
is in the user's command path, and then ``trampoline'' using is in the user's command path, and then ``trampoline'' using
@exec{/usr/bin/env}: @exec{/usr/bin/env}:
@verbatim[#:indent 2]{ @verbatim[#:indent 2]{
#! /usr/bin/env mzscheme #! /usr/bin/env racket
#lang scheme/base #lang racket/base
"Hello, world!" "Hello, world!"
} }
In either case, command-line arguments to a script are available via In either case, command-line arguments to a script are available via
@scheme[current-command-line-arguments]: @racket[current-command-line-arguments]:
@verbatim[#:indent 2]{ @verbatim[#:indent 2]{
#! /usr/bin/env mzscheme #! /usr/bin/env racket
#lang scheme/base #lang racket/base
(printf "Given arguments: ~s\n" (printf "Given arguments: ~s\n"
(current-command-line-arguments)) (current-command-line-arguments))
} }
If the name of the script is needed, it is available via If the name of the script is needed, it is available via
@scheme[(find-system-path 'run-file)], instead of via @racket[(find-system-path 'run-file)], instead of via
@scheme[(current-command-line-arguments)]. @racket[(current-command-line-arguments)].
Usually, then best way to handle command-line arguments is to parse Usually, then best way to handle command-line arguments is to parse
them using the @scheme[command-line] form provided by them using the @racket[command-line] form provided by
@schememodname[scheme]. The @scheme[command-line] form extracts @racketmodname[racket]. The @racket[command-line] form extracts
command-line arguments from @scheme[(current-command-line-arguments)] command-line arguments from @racket[(current-command-line-arguments)]
by default: by default:
@verbatim[#:indent 2]{ @verbatim[#:indent 2]{
#! /usr/bin/env mzscheme #! /usr/bin/env racket
#lang scheme #lang racket
(define verbose? (make-parameter #f)) (define verbose? (make-parameter #f))
@ -95,47 +95,47 @@ command-line arguments are allowed by the script.
An even more general trampoline uses @exec{/bin/sh} plus some lines An even more general trampoline uses @exec{/bin/sh} plus some lines
that are comments in one language and expressions in the other. This that are comments in one language and expressions in the other. This
trampoline is more complicated, but it provides more control over trampoline is more complicated, but it provides more control over
command-line arguments to @exec{mzscheme}: command-line arguments to @exec{racket}:
@verbatim[#:indent 2]|{ @verbatim[#:indent 2]|{
#! /bin/sh #! /bin/sh
#| #|
exec mzscheme -cu "$0" ${1+"$@"} exec racket -cu "$0" ${1+"$@"}
|# |#
#lang scheme/base #lang racket/base
(printf "This script started slowly, because the use of\n") (printf "This script started slowly, because the use of\n")
(printf "bytecode files has been disabled via -c.\n") (printf "bytecode files has been disabled via -c.\n")
(printf "Given arguments: ~s\n" (printf "Given arguments: ~s\n"
(current-command-line-arguments)) (current-command-line-arguments))
}| }|
Note that @litchar{#!} starts a line comment in Scheme, and Note that @litchar{#!} starts a line comment in Racket, and
@litchar{#|}...@litchar{|#} forms a block comment. Meanwhile, @litchar{#|}...@litchar{|#} forms a block comment. Meanwhile,
@litchar{#} also starts a shell-script comment, while @exec{exec @litchar{#} also starts a shell-script comment, while @exec{exec
mzscheme} aborts the shell script to start @exec{mzscheme}. That way, racket} aborts the shell script to start @exec{racket}. That way,
the script file turns out to be valid input to both @exec{/bin/sh} and the script file turns out to be valid input to both @exec{/bin/sh} and
@exec{mzscheme}. @exec{racket}.
@section{Windows Batch Files} @section{Windows Batch Files}
A similar trick can be used to write Scheme code in Windows A similar trick can be used to write Racket code in Windows
@as-index{@tt{.bat}} batch files: @as-index{@tt{.bat}} batch files:
@verbatim[#:indent 2]|{ @verbatim[#:indent 2]|{
; @echo off ; @echo off
; MzScheme.exe "%~f0" %* ; Racket.exe "%~f0" %*
; exit /b ; exit /b
#lang scheme/base #lang racket/base
"Hello, world!" "Hello, world!"
}| }|
@;{ @;{
Original trick from Ben Goetter, who used: Original trick from Ben Goetter, who used:
; @echo off && REM -*- scheme -*- ; @echo off && REM -*- racket -*-
; "%MZSCHEME%" "%~f0" %* ; "%RACKET%" "%~f0" %*
; exit /b ; exit /b
#lang scheme #lang racket
... ...
it might be worth documenting the Emacs "-*-" convention and a way to it might be worth documenting the Emacs "-*-" convention and a way to

View File

@ -33,8 +33,8 @@ The following kinds of values are serializable:
@itemize[ @itemize[
@item{structures created through @scheme[define-serializable-struct] or @item{structures created through @scheme[serializable-struct] or
@scheme[define-serializable-struct/version], or more generally @scheme[serializable-struct/versions], or more generally
structures with the @scheme[prop:serializable] property (see structures with the @scheme[prop:serializable] property (see
@scheme[prop:serializable] for more information);} @scheme[prop:serializable] for more information);}
@ -338,10 +338,10 @@ exception to disallow the @scheme[dynamic-require].}
@; ---------------------------------------------------------------------- @; ----------------------------------------------------------------------
@defform[(define-serializable-struct id-maybe-super (field ...) @defform[(serializable-struct id maybe-super (field ...)
struct-option ...)]{ struct-option ...)]{
Like @scheme[define-struct], but instances of the structure type are Like @scheme[struct], but instances of the structure type are
serializable with @scheme[serialize]. This form is allowed only at serializable with @scheme[serialize]. This form is allowed only at
the top level or in a module's top level (so that deserialization the top level or in a module's top level (so that deserialization
information can be found later). information can be found later).
@ -350,17 +350,16 @@ Serialization only supports cycles involving the created structure
type when all fields are mutable (or when the cycle can be broken type when all fields are mutable (or when the cycle can be broken
through some other mutable value). through some other mutable value).
In addition to the bindings generated by @scheme[define-struct], In addition to the bindings generated by @scheme[struct],
@scheme[define-serializable-struct] binds @scheme[serializable-struct] binds
@schemeidfont{deserialize-info:}@scheme[_id]@schemeidfont{-v0} to @schemeidfont{deserialize-info:}@scheme[_id]@schemeidfont{-v0} to
deserialization information. Furthermore, in a module context, it deserialization information. Furthermore, in a module context, it
automatically @scheme[provide]s this binding. automatically @scheme[provide]s this binding.
The @scheme[define-serializable-struct] form enables the construction The @scheme[serializable-struct] form enables the construction of
of structure instances from places where structure instances from places where @scheme[id] is not accessible,
@schemeidfont{make}@scheme[id] is not accessible, since since deserialization must construct instances. Furthermore,
deserialization must construct instances. Furthermore, @scheme[serializable-struct] provides limited access to field
@scheme[define-serializable-struct] provides limited access to field
mutation, but only for instances generated through the deserialization mutation, but only for instances generated through the deserialization
information bound to information bound to
@schemeidfont{deserialize-info:}@scheme[_id]@schemeidfont{-v0}. See @schemeidfont{deserialize-info:}@scheme[_id]@schemeidfont{-v0}. See
@ -368,9 +367,9 @@ information bound to
The @scheme[-v0] suffix on the deserialization enables future The @scheme[-v0] suffix on the deserialization enables future
versioning on the structure type through versioning on the structure type through
@scheme[define-serializable-struct/version]. @scheme[serializable-struct/version].
When a supertype is supplied in @scheme[id-maybe-super] is supplied, When a supertype is supplied in @scheme[maybe-super] is supplied,
compile-time information bound to the supertype identifier must compile-time information bound to the supertype identifier must
include all of the supertype's field accessors. If any field mutator include all of the supertype's field accessors. If any field mutator
is missing, the structure type will be treated as immutable for the is missing, the structure type will be treated as immutable for the
@ -379,20 +378,28 @@ structure type cannot be handled by the deserializer).
@examples[ @examples[
#:eval ser-eval #:eval ser-eval
(define-serializable-struct point (x y)) (serializable-struct point (x y))
(point-x (deserialize (serialize (make-point 1 2)))) (point-x (deserialize (serialize (point 1 2))))
]} ]}
@; ---------------------------------------------------------------------- @; ----------------------------------------------------------------------
@defform/subs[(define-serializable-struct/versions id-maybe-super vers (field ...) @defform[(define-serializable-struct id-maybe-super (field ...)
(other-version-clause ...) struct-option ...)]{
struct-option ...)
Like @racket[serializable-struct], but with the supertype syntax and
default constructor name of @racket[define-struct].}
@; ----------------------------------------------------------------------
@defform/subs[(serializable-struct/versions id-maybe-super vers (field ...)
(other-version-clause ...)
struct-option ...)
([other-version-clause (other-vers make-proc-expr ([other-version-clause (other-vers make-proc-expr
cycle-make-proc-expr)])]{ cycle-make-proc-expr)])]{
Like @scheme[define-serializable-struct], but the generated Like @scheme[serializable-struct], but the generated deserializer
deserializer binding is binding is
@schemeidfont{deserialize-info:}@scheme[_id]@schemeidfont{-v}@scheme[vers]. In @schemeidfont{deserialize-info:}@scheme[_id]@schemeidfont{-v}@scheme[vers]. In
addition, addition,
@schemeidfont{deserialize-info:}@scheme[_id]@schemeidfont{-v}@scheme[other-vers] @schemeidfont{deserialize-info:}@scheme[_id]@schemeidfont{-v}@scheme[other-vers]
@ -410,35 +417,44 @@ instance of @scheme[id] and copies its field values into @scheme[x].
@examples[ @examples[
#:eval ser-eval #:eval ser-eval
(define-serializable-struct point (x y) #:mutable #:transparent) (serializable-struct point (x y) #:mutable #:transparent)
(define ps (serialize (make-point 1 2))) (define ps (serialize (point 1 2)))
(deserialize ps) (deserialize ps)
(define x (make-point 1 10)) (define x (point 1 10))
(set-point-x! x x) (set-point-x! x x)
(define xs (serialize x)) (define xs (serialize x))
(deserialize xs) (deserialize xs)
(define-serializable-struct/versions point 1 (x y z) (serializable-struct/versions point 1 (x y z)
([0 ([0
(code:comment @#,t{Constructor for simple v0 instances:}) (code:comment @#,t{Constructor for simple v0 instances:})
(lambda (x y) (make-point x y 0)) (lambda (x y) (point x y 0))
(code:comment @#,t{Constructor for v0 instance in a cycle:}) (code:comment @#,t{Constructor for v0 instance in a cycle:})
(lambda () (lambda ()
(let ([p0 (make-point #f #f 0)]) (let ([p0 (point #f #f 0)])
(values (values
p0 p0
(lambda (p) (lambda (p)
(set-point-x! p0 (point-x p)) (set-point-x! p0 (point-x p))
(set-point-y! p0 (point-y p))))))]) (set-point-y! p0 (point-y p))))))])
#:mutable #:transparent) #:mutable #:transparent)
(deserialize (serialize (make-point 4 5 6))) (deserialize (serialize (point 4 5 6)))
(deserialize ps) (deserialize ps)
(deserialize xs) (deserialize xs)
]} ]}
@; ---------------------------------------------------------------------- @; ----------------------------------------------------------------------
@defform[(define-serializable-struct/versions id-maybe-super vers (field ...)
(other-version-clause ...)
struct-option ...)]{
Like @racket[serializable-struct/versions], but with the supertype syntax and
default constructor name of @racket[define-struct].}
}
@; ----------------------------------------------------------------------
@defproc[(make-deserialize-info [make procedure?] @defproc[(make-deserialize-info [make procedure?]
[cycle-make (-> (values any/c procedure?))]) [cycle-make (-> (values any/c procedure?))])
any]{ any]{

View File

@ -2,7 +2,7 @@
(provide all-contract-tests) (provide all-contract-tests)
(require rktunit (require racunit
deinprogramm/define-record-procedures deinprogramm/define-record-procedures
deinprogramm/contract/contract deinprogramm/contract/contract
deinprogramm/contract/contract-syntax) deinprogramm/contract/contract-syntax)

View File

@ -2,7 +2,7 @@
(provide all-image-tests) (provide all-image-tests)
(require rktunit (require racunit
deinprogramm/image deinprogramm/image
(only-in lang/private/imageeq image=?) (only-in lang/private/imageeq image=?)
mred mred

View File

@ -1,6 +1,6 @@
#lang scheme/base #lang scheme/base
(require rktunit/text-ui) (require racunit/text-ui)
(require tests/deinprogramm/contract) (require tests/deinprogramm/contract)
(run-tests all-contract-tests) (run-tests all-contract-tests)

View File

@ -1,6 +1,6 @@
#lang scheme/base #lang scheme/base
(require rktunit/text-ui) (require racunit/text-ui)
(require tests/deinprogramm/image) (require tests/deinprogramm/image)
(run-tests all-image-tests) (run-tests all-image-tests)

View File

@ -216,7 +216,7 @@
=> '(#"1 test passed\n" #"2 tests passed\n") => '(#"1 test passed\n" #"2 tests passed\n")
) )
;; RktUnit stuff ;; RacUnit stuff
;; (examples that should fail modified to ones that shouldn't) ;; (examples that should fail modified to ones that shouldn't)
#| #|

View File

@ -1,7 +1,7 @@
#lang scheme/base #lang scheme/base
(require scheme/future (require scheme/future
rktunit) racunit)
#|Need to add expressions which raise exceptions inside a #|Need to add expressions which raise exceptions inside a
future thunk which can be caught at the touch site future thunk which can be caught at the touch site

View File

@ -1,6 +1,6 @@
#lang racket #lang racket
(require rktunit (require racunit
rktunit/text-ui racunit/text-ui
net/url net/url
(prefix-in h: html) (prefix-in h: html)
(prefix-in x: xml)) (prefix-in x: xml))

View File

@ -21,7 +21,7 @@
"plot" "plot"
"profj" "profj"
"r6rs" "r6rs"
"rktunit" "racunit"
"srfi" "srfi"
"srpersist" "srpersist"
"stepper" "stepper"

View File

@ -1,6 +1,6 @@
#lang scheme/base #lang scheme/base
(require rktunit (require racunit
rktunit/gui) racunit/gui)
(require macro-debugger/model/debug (require macro-debugger/model/debug
"gentest-framework.ss" "gentest-framework.ss"
"gentests.ss" "gentests.ss"

View File

@ -1,5 +1,5 @@
#lang scheme/base #lang scheme/base
(require rktunit) (require racunit)
(require macro-debugger/model/debug (require macro-debugger/model/debug
macro-debugger/model/stx-util macro-debugger/model/stx-util
"gentest-framework.ss" "gentest-framework.ss"

View File

@ -1,6 +1,6 @@
#lang scheme/base #lang scheme/base
(require rktunit (require racunit
rktunit/gui) racunit/gui)
(require macro-debugger/model/debug (require macro-debugger/model/debug
scheme/path scheme/path
scheme/gui) scheme/gui)

View File

@ -1,5 +1,5 @@
#lang scheme/base #lang scheme/base
(require rktunit) (require racunit)
(require macro-debugger/model/debug (require macro-debugger/model/debug
"../test-setup.ss") "../test-setup.ss")
(provide specialized-hiding-tests) (provide specialized-hiding-tests)

View File

@ -1,5 +1,5 @@
#lang scheme/base #lang scheme/base
(require rktunit) (require racunit)
(require macro-debugger/model/debug (require macro-debugger/model/debug
"../test-setup.ss") "../test-setup.ss")
(provide policy-tests) (provide policy-tests)

View File

@ -1,5 +1,5 @@
#lang scheme/base #lang scheme/base
(require rktunit) (require racunit)
(require macro-debugger/model/debug (require macro-debugger/model/debug
macro-debugger/model/steps macro-debugger/model/steps
"../test-setup.ss") "../test-setup.ss")

View File

@ -6,7 +6,7 @@
(for-syntax scheme/base) (for-syntax scheme/base)
(prefix-in m: mzlib/match) (prefix-in m: mzlib/match)
(only-in srfi/13 string-contains) (only-in srfi/13 string-contains)
rktunit) racunit)
(define-syntax (comp stx) (define-syntax (comp stx)
(syntax-case stx () (syntax-case stx ()

View File

@ -1,5 +1,5 @@
(module match-tests mzscheme (module match-tests mzscheme
(require mzlib/match rktunit) (require mzlib/match racunit)
(provide match-tests) (provide match-tests)

View File

@ -1,6 +1,6 @@
(module other-plt-tests mzscheme (module other-plt-tests mzscheme
(require rktunit net/uri-codec mzlib/pregexp mzlib/plt-match (require racunit net/uri-codec mzlib/pregexp mzlib/plt-match
mzlib/list mzlib/etc) mzlib/list mzlib/etc)
(define-struct shape (color)) (define-struct shape (color))

View File

@ -1,5 +1,5 @@
(module other-tests mzscheme (module other-tests mzscheme
(require mzlib/match rktunit) (require mzlib/match racunit)
(provide other-tests) (provide other-tests)

Some files were not shown because too many files have changed in this diff Show More