Merge remote branch 'origin/master' into samth/new-logic2
Conflicts: collects/tests/typed-scheme/unit-tests/typecheck-tests.rkt
This commit is contained in:
commit
5e9ae84b15
|
@ -1,6 +1,6 @@
|
|||
#lang scheme/load
|
||||
|
||||
(require rktunit)
|
||||
(require racunit)
|
||||
(require 2htdp/batch-io)
|
||||
|
||||
(define file "batch-io.txt")
|
||||
|
|
|
@ -45,7 +45,7 @@
|
|||
scheme/math
|
||||
scheme/class
|
||||
scheme/gui/base
|
||||
rktunit
|
||||
racunit
|
||||
(prefix-in 1: htdp/image)
|
||||
(only-in lang/htdp-advanced equal~?))
|
||||
|
||||
|
|
|
@ -662,7 +662,7 @@ mz-extras :+= (- (package: "unstable")
|
|||
;; -------------------- plai
|
||||
plt-extras :+= (package: "plai/")
|
||||
|
||||
plt-extras :+= (package: "rktunit/")
|
||||
plt-extras :+= (package: "racunit/")
|
||||
plt-extras :+= (package: "schemeunit/")
|
||||
|
||||
;; ============================================================================
|
||||
|
|
|
@ -615,26 +615,26 @@
|
|||
("schematics" "port.plt" 1 0 #f)
|
||||
("schematics" "random.plt" 1 0 #f)
|
||||
("schematics" "sake.plt" 1 0 "4.0")
|
||||
("schematics" "rktunit.plt" 3 4 "4.0")
|
||||
("schematics" "rktunit.plt" 3 3 "4.0")
|
||||
("schematics" "rktunit.plt" 3 2 "4.0")
|
||||
("schematics" "rktunit.plt" 3 1 "4.0")
|
||||
("schematics" "rktunit.plt" 3 0 "4.0")
|
||||
("schematics" "rktunit.plt" 2 11 "4.1.0.3")
|
||||
("schematics" "rktunit.plt" 2 10 "369.1")
|
||||
("schematics" "rktunit.plt" 2 9 "369.1")
|
||||
("schematics" "rktunit.plt" 2 8 "369.1")
|
||||
("schematics" "rktunit.plt" 2 7 "369.1")
|
||||
("schematics" "rktunit.plt" 2 6 "369.1")
|
||||
("schematics" "rktunit.plt" 2 5 "369.1")
|
||||
("schematics" "rktunit.plt" 2 4 "369.1")
|
||||
("schematics" "rktunit.plt" 2 3 #f)
|
||||
("schematics" "rktunit.plt" 2 2 #f)
|
||||
("schematics" "rktunit.plt" 2 1 #f)
|
||||
("schematics" "rktunit.plt" 2 0 #f)
|
||||
("schematics" "rktunit.plt" 1 2 #f)
|
||||
("schematics" "rktunit.plt" 1 1 #f)
|
||||
("schematics" "rktunit.plt" 1 0 #f)
|
||||
("schematics" "racunit.plt" 3 4 "4.0")
|
||||
("schematics" "racunit.plt" 3 3 "4.0")
|
||||
("schematics" "racunit.plt" 3 2 "4.0")
|
||||
("schematics" "racunit.plt" 3 1 "4.0")
|
||||
("schematics" "racunit.plt" 3 0 "4.0")
|
||||
("schematics" "racunit.plt" 2 11 "4.1.0.3")
|
||||
("schematics" "racunit.plt" 2 10 "369.1")
|
||||
("schematics" "racunit.plt" 2 9 "369.1")
|
||||
("schematics" "racunit.plt" 2 8 "369.1")
|
||||
("schematics" "racunit.plt" 2 7 "369.1")
|
||||
("schematics" "racunit.plt" 2 6 "369.1")
|
||||
("schematics" "racunit.plt" 2 5 "369.1")
|
||||
("schematics" "racunit.plt" 2 4 "369.1")
|
||||
("schematics" "racunit.plt" 2 3 #f)
|
||||
("schematics" "racunit.plt" 2 2 #f)
|
||||
("schematics" "racunit.plt" 2 1 #f)
|
||||
("schematics" "racunit.plt" 2 0 #f)
|
||||
("schematics" "racunit.plt" 1 2 #f)
|
||||
("schematics" "racunit.plt" 1 1 #f)
|
||||
("schematics" "racunit.plt" 1 0 #f)
|
||||
("schematics" "si.plt" 1 0 #f)
|
||||
("schematics" "spgsql.plt" 2 3 "371.3")
|
||||
("schematics" "spgsql.plt" 2 2 "371.3")
|
||||
|
|
|
@ -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/match" 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/rktunit/gui.rkt" responsible (ryanc) drdr:command-line "mred-text -t ~s"
|
||||
"collects/rktunit/private/gui" responsible (ryanc)
|
||||
"collects/rktunit/private/gui/config.rkt" drdr:command-line "mred-text -t ~s"
|
||||
"collects/rktunit/private/gui/controller.rkt" drdr:command-line "mred-text -t ~s"
|
||||
"collects/rktunit/private/gui/gui.rkt" drdr:command-line "mred-text -t ~s"
|
||||
"collects/rktunit/private/gui/model2rml.rkt" drdr:command-line "mred-text -t ~s"
|
||||
"collects/rktunit/private/gui/rml.rkt" drdr:command-line "mred-text -t ~s"
|
||||
"collects/rktunit/private/gui/view.rkt" drdr:command-line "mred-text -t ~s"
|
||||
"collects/rktunit/tool.rkt" responsible (ryanc) drdr:command-line "mred-text -t ~s"
|
||||
"collects/schemeunit/gui.rkt" responsible (jay) drdr:command-line "mred-text -t ~s"
|
||||
"collects/racunit/gui.rkt" responsible (ryanc) drdr:command-line "mred-text -t ~s"
|
||||
"collects/racunit/private/gui" responsible (ryanc)
|
||||
"collects/racunit/private/gui/config.rkt" drdr:command-line "mred-text -t ~s"
|
||||
"collects/racunit/private/gui/controller.rkt" drdr:command-line "mred-text -t ~s"
|
||||
"collects/racunit/private/gui/gui.rkt" drdr:command-line "mred-text -t ~s"
|
||||
"collects/racunit/private/gui/model2rml.rkt" drdr:command-line "mred-text -t ~s"
|
||||
"collects/racunit/private/gui/rml.rkt" 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/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
|
||||
|
@ -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/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/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/40/run-tests.rkt" drdr:command-line "mzscheme -f ~s"
|
||||
"collects/tests/srfi/43/run-tests.rkt" drdr:command-line "mzscheme -f ~s"
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#lang scheme/base
|
||||
(require (for-syntax scheme/base)
|
||||
"../lex.ss"
|
||||
rktunit)
|
||||
racunit)
|
||||
|
||||
(define-syntax (catch-syn-error stx)
|
||||
(syntax-case stx ()
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
(unpack-blame pos)
|
||||
"<<unknown party>>"
|
||||
#t
|
||||
name)
|
||||
"<<unknown party>>")
|
||||
x
|
||||
fmt
|
||||
args))
|
||||
|
@ -60,7 +60,7 @@
|
|||
(unpack-blame (if original? pos neg))
|
||||
(unpack-blame (if original? neg pos))
|
||||
original?
|
||||
name)))))
|
||||
(unpack-blame (if original? neg pos)))))))
|
||||
|
||||
(define (legacy-property name)
|
||||
(define-values [ prop pred get ]
|
||||
|
|
|
@ -5,13 +5,15 @@
|
|||
racket/struct-info))
|
||||
|
||||
(provide (all-from-out "private/serialize.ss")
|
||||
serializable-struct
|
||||
serializable-struct/versions
|
||||
define-serializable-struct
|
||||
define-serializable-struct/versions)
|
||||
|
||||
(define-syntax (define-serializable-struct/versions/derived stx)
|
||||
(syntax-case stx ()
|
||||
;; First check `id/sup':
|
||||
[(_ orig-stx id/sup . _)
|
||||
[(_ orig-stx make-prefix? id/sup . _)
|
||||
(not (or (identifier? #'id/sup)
|
||||
(syntax-case #'id/sup ()
|
||||
[(id sup) (and (identifier? #'id)
|
||||
|
@ -22,11 +24,11 @@
|
|||
;; Not valid, so let `define-struct/derived' complain:
|
||||
#'(define-struct/derived orig-stx id/sup ())]
|
||||
;; Check version:
|
||||
[(_ orig-stx id/sup vers . _)
|
||||
[(_ orig-stx make-prefix? id/sup vers . _)
|
||||
(not (exact-nonnegative-integer? (syntax-e #'vers)))
|
||||
(raise-syntax-error #f "expected a nonnegative exact integer for a version" #'orig-stx #'vers)]
|
||||
;; 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 ...)
|
||||
(let* ([id (if (identifier? #'id/sup)
|
||||
#'id/sup
|
||||
|
@ -35,10 +37,22 @@
|
|||
#f
|
||||
(extract-struct-info (syntax-local-value (cadr (syntax->list #'id/sup)))))]
|
||||
[fields (syntax->list #'(field ...))]
|
||||
[maker (datum->syntax id
|
||||
[given-maker (let loop ([props (syntax->list #'(prop ...))])
|
||||
(cond
|
||||
[(null? props) #f]
|
||||
[(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)
|
||||
id))]
|
||||
[getters (map (lambda (field)
|
||||
(datum->syntax
|
||||
id
|
||||
|
@ -103,6 +117,10 @@
|
|||
id/sup
|
||||
(field ...)
|
||||
prop ...
|
||||
#,@(if (or given-maker
|
||||
(syntax-e #'make-prefix?))
|
||||
null
|
||||
(list #'#:constructor-name id))
|
||||
#:property prop:serializable
|
||||
(make-serialize-info
|
||||
;; The struct-to-vector function: --------------------
|
||||
|
@ -203,14 +221,38 @@
|
|||
(define-syntax (define-serializable-struct/versions stx)
|
||||
(syntax-case stx ()
|
||||
[(_ . 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)
|
||||
(syntax-case stx ()
|
||||
[(_ id/sup (field ...) prop ...)
|
||||
#`(define-serializable-struct/versions/derived #,stx
|
||||
#`(define-serializable-struct/versions/derived #,stx #t
|
||||
id/sup 0 (field ...) () prop ...)]
|
||||
[(_ . 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 ...)]))
|
||||
|
||||
)
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
(define (test/gui . 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
|
||||
[test/gui
|
|
@ -1,13 +1,13 @@
|
|||
#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")))
|
||||
|
||||
(define scribblings '(("scribblings/rktunit.scrbl" (multi-page) (tool))))
|
||||
(define scribblings '(("scribblings/racunit.scrbl" (multi-page) (tool))))
|
||||
(define tools '[("tool.rkt")])
|
||||
(define tool-names '["RktUnit DrRacket integration"])
|
||||
(define tool-names '["RacUnit DrRacket integration"])
|
||||
|
||||
(define homepage "http://schematics.sourceforge.net/")
|
||||
(define url "http://schematics.sourceforge.net/")
|
|
@ -4,10 +4,10 @@
|
|||
|
||||
;; struct test :
|
||||
(define-struct test ())
|
||||
;; struct (rktunit-test-case test) : (U string #f) thunk
|
||||
(define-struct (rktunit-test-case test) (name action) #:transparent)
|
||||
;; struct (rktunit-test-suite test) : string (fdown fup fhere seed -> (listof test-result)) thunk thunk
|
||||
(define-struct (rktunit-test-suite test) (name tests before after) #:transparent)
|
||||
;; struct (racunit-test-case test) : (U string #f) thunk
|
||||
(define-struct (racunit-test-case test) (name action) #:transparent)
|
||||
;; struct (racunit-test-suite test) : string (fdown fup fhere seed -> (listof test-result)) thunk thunk
|
||||
(define-struct (racunit-test-suite test) (name tests before after) #:transparent)
|
||||
|
||||
;; struct exn:test exn : ()
|
||||
;;
|
||||
|
@ -33,10 +33,10 @@
|
|||
(define-struct (test-success test-result) (result))
|
||||
|
||||
(provide/contract
|
||||
(struct (rktunit-test-case test)
|
||||
(struct (racunit-test-case test)
|
||||
((name (or/c string? false/c))
|
||||
(action (-> any))))
|
||||
(struct (rktunit-test-suite test)
|
||||
(struct (racunit-test-suite test)
|
||||
((name string?)
|
||||
(tests procedure?)
|
||||
(before (-> any))
|
|
@ -11,7 +11,7 @@
|
|||
;; Infrastructure ----------------------------------------------
|
||||
|
||||
;; 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))
|
||||
(define (check-info-stack marks)
|
|
@ -5,20 +5,20 @@
|
|||
|
||||
;; Frame size preferences
|
||||
|
||||
(preferences:set-default 'rktunit:frame:width 400 exact-positive-integer?)
|
||||
(preferences:set-default 'rktunit:frame:height 400 exact-positive-integer?)
|
||||
(define pref:width (pref:get/set 'rktunit:frame:width))
|
||||
(define pref:height (pref:get/set 'rktunit:frame:height))
|
||||
(preferences:set-default 'racunit:frame:width 400 exact-positive-integer?)
|
||||
(preferences:set-default 'racunit:frame:height 400 exact-positive-integer?)
|
||||
(define pref:width (pref:get/set 'racunit:frame:width))
|
||||
(define pref:height (pref:get/set 'racunit:frame:height))
|
||||
|
||||
;; CONSTANTS
|
||||
;; Some of these are obsolete, given the preferences above.
|
||||
|
||||
(define DETAILS-CANVAS-INIT-WIDTH 400)
|
||||
(define FRAME-LABEL "RktUnit")
|
||||
(define FRAME-LABEL "RacUnit")
|
||||
(define FRAME-INIT-HEIGHT 400)
|
||||
(define TREE-INIT-WIDTH 240)
|
||||
(define TREE-COLORIZE-CASES #t)
|
||||
(define DIALOG-ERROR-TITLE "RktUnit: Error")
|
||||
(define DIALOG-ERROR-TITLE "RacUnit: Error")
|
||||
(define STATUS-SUCCESS 'success)
|
||||
(define STATUS-FAILURE 'failure)
|
||||
(define STATUS-ERROR 'error)
|
|
@ -25,18 +25,18 @@
|
|||
;; create-model : test suite<%>/#f -> result<%>
|
||||
(define/public (create-model test parent)
|
||||
(define result
|
||||
(cond [(rktunit-test-case? test)
|
||||
(cond [(racunit-test-case? test)
|
||||
(new case-result%
|
||||
(controller this)
|
||||
(test test)
|
||||
(name (or (rktunit-test-case-name test)
|
||||
(name (or (racunit-test-case-name test)
|
||||
"<unnamed test-case>"))
|
||||
(parent parent))]
|
||||
[(rktunit-test-suite? test)
|
||||
[(racunit-test-suite? test)
|
||||
(new suite-result%
|
||||
(controller this)
|
||||
(test test)
|
||||
(name (or (rktunit-test-suite-name test)
|
||||
(name (or (racunit-test-suite-name test)
|
||||
"<unnamed test-suite>"))
|
||||
(parent parent))]))
|
||||
(send/i view view<%> create-view-link result parent)
|
|
@ -48,8 +48,8 @@
|
|||
#|
|
||||
(define/public (run)
|
||||
(let ([custodian (make-custodian)]
|
||||
[before (rktunit-test-suite-before test)]
|
||||
[after (rktunit-test-suite-after test)])
|
||||
[before (racunit-test-suite-before test)]
|
||||
[after (racunit-test-suite-after test)])
|
||||
(parameterize [(current-custodian custodian)]
|
||||
(dynamic-wind
|
||||
before
|
||||
|
@ -112,8 +112,8 @@
|
|||
(call-with-continuation-prompt
|
||||
(lambda ()
|
||||
(time-apply run-test-case
|
||||
(list (rktunit-test-case-name test)
|
||||
(rktunit-test-case-action test)))))])
|
||||
(list (racunit-test-case-name test)
|
||||
(racunit-test-case-action test)))))])
|
||||
(values (car results) (list cputime realtime gctime))))
|
||||
|
||||
(define (make-output-ports)
|
Before Width: | Height: | Size: 513 B After Width: | Height: | Size: 513 B |
|
@ -7,7 +7,7 @@
|
|||
|
||||
(provide insert-text
|
||||
ext:text%
|
||||
rktunit-style-map)
|
||||
racunit-style-map)
|
||||
|
||||
;; insert-text : text% string style-delta% -> void
|
||||
(define (insert-text e text style)
|
||||
|
@ -20,7 +20,7 @@
|
|||
|
||||
(define ext:text-mixin
|
||||
(mixin (text<%>) ()
|
||||
(init-field (style-map rktunit-style-map))
|
||||
(init-field (style-map racunit-style-map))
|
||||
(inherit last-position
|
||||
change-style
|
||||
set-clickback
|
||||
|
@ -139,7 +139,7 @@
|
|||
[error . ,style:red]
|
||||
[value . ,style:darkblue]))
|
||||
|
||||
(define rktunit-styles
|
||||
(define racunit-styles
|
||||
`([test-unexecuted . ,style:gray]
|
||||
[test-success . ,style:green]
|
||||
[test-failure . ,style:red]
|
||||
|
@ -181,7 +181,7 @@
|
|||
(extend-style-map empty-style-map
|
||||
basic-styles))
|
||||
|
||||
;; rktunit-style-map : style-map<%>
|
||||
(define rktunit-style-map
|
||||
;; racunit-style-map : style-map<%>
|
||||
(define racunit-style-map
|
||||
(extend-style-map basic-style-map
|
||||
rktunit-styles))
|
||||
racunit-styles))
|
|
@ -13,7 +13,7 @@
|
|||
(provide make-view-frame
|
||||
view%)
|
||||
|
||||
(define style-map rktunit-style-map)
|
||||
(define style-map racunit-style-map)
|
||||
|
||||
#|
|
||||
|
||||
|
@ -50,7 +50,7 @@ still be there, just not visible?
|
|||
controller)
|
||||
(super-new)
|
||||
|
||||
(define editor (new ext:text% (style-map rktunit-style-map)))
|
||||
(define editor (new ext:text% (style-map racunit-style-map)))
|
||||
(define renderer
|
||||
(new model-renderer%
|
||||
(controller controller)
|
||||
|
@ -146,7 +146,7 @@ still be there, just not visible?
|
|||
;; If the view-link has not been created,
|
||||
;; yield until it is.
|
||||
(unless (yield)
|
||||
(error 'rktunit-gui
|
||||
(error 'racunit-gui
|
||||
"internal error: no progress waiting for view-link"))
|
||||
(do-model-update model)])))
|
||||
|
|
@ -51,12 +51,12 @@
|
|||
;; data so FP is a bit ugly].
|
||||
(define (foldts fdown fup fhere seed test)
|
||||
(cond
|
||||
((rktunit-test-case? test)
|
||||
((racunit-test-case? test)
|
||||
(fhere test
|
||||
(rktunit-test-case-name test)
|
||||
(rktunit-test-case-action test)
|
||||
(racunit-test-case-name test)
|
||||
(racunit-test-case-action test)
|
||||
seed))
|
||||
((rktunit-test-suite? test)
|
||||
((racunit-test-suite? test)
|
||||
(apply-test-suite test fdown fup fhere seed))
|
||||
(else
|
||||
(raise
|
|
@ -27,14 +27,14 @@
|
|||
(define (test-suite-test-case-around fhere)
|
||||
(lambda (thunk)
|
||||
(let* ([name (current-test-name)]
|
||||
[test (make-rktunit-test-case name thunk)]
|
||||
[test (make-racunit-test-case name thunk)]
|
||||
[seed (current-seed)])
|
||||
(current-seed (fhere test name thunk seed)))))
|
||||
|
||||
(define (test-suite-check-around fhere)
|
||||
(lambda (thunk)
|
||||
(let* ([name #f]
|
||||
[test (make-rktunit-test-case name thunk)]
|
||||
[test (make-racunit-test-case name thunk)]
|
||||
[seed (current-seed)])
|
||||
(current-seed (fhere test name thunk seed)))))
|
||||
|
||||
|
@ -42,12 +42,12 @@
|
|||
(define delayed-test-case-around
|
||||
(lambda (thunk)
|
||||
(let ([name (current-test-name)])
|
||||
(make-rktunit-test-case name thunk))))
|
||||
(make-racunit-test-case name thunk))))
|
||||
|
||||
(define delayed-check-around
|
||||
(lambda (thunk)
|
||||
(let ([name #f])
|
||||
(make-rktunit-test-case name thunk))))
|
||||
(make-racunit-test-case name thunk))))
|
||||
|
||||
(define-syntax delay-test
|
||||
(syntax-rules ()
|
||||
|
@ -58,12 +58,12 @@
|
|||
test test1 ...)]))
|
||||
|
||||
(define (apply-test-suite suite fdown fup fhere seed)
|
||||
(let* ([name (rktunit-test-suite-name suite)]
|
||||
[tests (rktunit-test-suite-tests suite)]
|
||||
[before (rktunit-test-suite-before suite)]
|
||||
[after (rktunit-test-suite-after suite)]
|
||||
(let* ([name (racunit-test-suite-name suite)]
|
||||
[tests (racunit-test-suite-tests suite)]
|
||||
[before (racunit-test-suite-before suite)]
|
||||
[after (racunit-test-suite-after suite)]
|
||||
[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)))
|
||||
|
||||
;; test-suite : name [#:before thunk] [#:after thunk] test ...
|
||||
|
@ -84,7 +84,7 @@
|
|||
[the-tests
|
||||
(lambda (fdown fup fhere seed)
|
||||
(define (run/inner x)
|
||||
(cond [(rktunit-test-suite? x)
|
||||
(cond [(racunit-test-suite? x)
|
||||
(current-seed
|
||||
(apply-test-suite x fdown fup fhere (current-seed)))]
|
||||
[(list? x)
|
||||
|
@ -103,7 +103,7 @@
|
|||
[(not (string? the-name))
|
||||
(raise-type-error 'test-suite "test-suite name as string" the-name)]
|
||||
[else
|
||||
(make-rktunit-test-suite
|
||||
(make-racunit-test-suite
|
||||
the-name
|
||||
the-tests
|
||||
before-thunk
|
||||
|
@ -138,13 +138,13 @@
|
|||
(for-each
|
||||
(lambda (t)
|
||||
(cond
|
||||
[(rktunit-test-suite? t)
|
||||
[(racunit-test-suite? t)
|
||||
(current-seed (apply-test-suite t fdown fup fhere (current-seed)))]
|
||||
[(rktunit-test-case? t)
|
||||
[(racunit-test-case? t)
|
||||
(current-seed
|
||||
(fhere t
|
||||
(rktunit-test-case-name t)
|
||||
(rktunit-test-case-action t)
|
||||
(racunit-test-case-name t)
|
||||
(racunit-test-case-action t)
|
||||
(current-seed)))]
|
||||
[else
|
||||
(raise
|
||||
|
@ -158,7 +158,7 @@
|
|||
;;
|
||||
;; Construct a test suite from a list of 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)
|
||||
before
|
||||
after))
|
|
@ -15,8 +15,8 @@
|
|||
(struct-out test-failure)
|
||||
(struct-out test-error)
|
||||
(struct-out test-success)
|
||||
(struct-out rktunit-test-case)
|
||||
(struct-out rktunit-test-suite)
|
||||
(struct-out racunit-test-case)
|
||||
(struct-out racunit-test-suite)
|
||||
|
||||
with-check-info
|
||||
with-check-info*
|
||||
|
@ -42,9 +42,9 @@
|
|||
test-suite
|
||||
make-test-suite
|
||||
delay-test
|
||||
(rename-out [make-rktunit-test-case make-test-case]
|
||||
[rktunit-test-case? test-case?]
|
||||
[rktunit-test-suite? test-suite?])
|
||||
(rename-out [make-racunit-test-case make-test-case]
|
||||
[racunit-test-case? test-case?]
|
||||
[racunit-test-suite? test-suite?])
|
||||
|
||||
define-test-suite
|
||||
define/provide-test-suite
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
@title{Acknowlegements}
|
||||
|
||||
The following people have contributed to RktUnit:
|
||||
The following people have contributed to RacUnit:
|
||||
|
||||
@itemize[
|
||||
@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]}
|
||||
|
||||
@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
|
||||
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
|
||||
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}
|
||||
|
||||
@item{Don Blaheta provided the method for grabbing line number
|
|
@ -1,10 +1,10 @@
|
|||
#lang scribble/doc
|
||||
@(require "base.rkt")
|
||||
|
||||
@title[#:tag "api"]{RktUnit API}
|
||||
@title[#:tag "api"]{RacUnit API}
|
||||
|
||||
@defmodule[rktunit
|
||||
#:use-sources (rktunit)]
|
||||
@defmodule[racunit
|
||||
#:use-sources (racunit)]
|
||||
|
||||
@include-section["overview.scrbl"]
|
||||
@include-section["check.scrbl"]
|
|
@ -6,15 +6,15 @@
|
|||
|
||||
(for-label scheme/base
|
||||
scheme/contract
|
||||
rktunit
|
||||
rktunit/text-ui
|
||||
rktunit/gui))
|
||||
racunit
|
||||
racunit/text-ui
|
||||
racunit/gui))
|
||||
|
||||
(provide
|
||||
(all-from-out scribble/eval
|
||||
scribble/manual)
|
||||
(for-label (all-from-out scheme/base
|
||||
scheme/contract
|
||||
rktunit
|
||||
rktunit/text-ui
|
||||
rktunit/gui)))
|
||||
racunit
|
||||
racunit/text-ui
|
||||
racunit/gui)))
|
|
@ -3,7 +3,7 @@
|
|||
|
||||
@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
|
||||
evaluates to @racket[#t]. If the condition doesn't hold the
|
||||
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
|
||||
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].
|
||||
|
||||
@defproc[(check (op (-> any any any))
|
|
@ -147,7 +147,7 @@ creates test cases within the suite, with the given names and
|
|||
body expressions.
|
||||
|
||||
As far I know no-one uses this macro, so it might disappear
|
||||
in future versions of RktUnit.}
|
||||
in future versions of RacUnit.}
|
||||
}
|
||||
|
||||
|
|
@ -48,5 +48,5 @@ file. The after action deletes it.
|
|||
This somewhat curious macro evaluates the given tests in a
|
||||
context where @racket[current-test-case-around] is
|
||||
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.}
|
|
@ -1,6 +1,6 @@
|
|||
#lang scheme/base
|
||||
|
||||
(require rktunit
|
||||
(require racunit
|
||||
"file.rkt")
|
||||
|
||||
(check-equal? (my-+ 1 1) 2)
|
|
@ -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!
|
||||
}
|
||||
|
||||
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[
|
||||
(require/expose rktunit/private/check-test (make-failure-test))
|
||||
(require/expose racunit/private/check-test (make-failure-test))
|
||||
]
|
|
@ -1,9 +1,9 @@
|
|||
#lang scribble/doc
|
||||
@(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[
|
||||
|
|
@ -1,10 +1,10 @@
|
|||
#lang scribble/doc
|
||||
@(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
|
||||
the evolution of the program under testing. RktUnit
|
||||
RacUnit is designed to allow tests to evolve in step with
|
||||
the evolution of the program under testing. RacUnit
|
||||
scales from the unstructed checks suitable for simple
|
||||
programs to the complex structure necessary for large
|
||||
projects.
|
||||
|
@ -25,9 +25,9 @@ checking are of the form:
|
|||
(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
|
||||
written in RktUnit as:
|
||||
written in RacUnit as:
|
||||
|
||||
@racketblock[
|
||||
(check-equal? (length null) 0)
|
||||
|
@ -35,7 +35,7 @@ written in RktUnit as:
|
|||
(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.
|
||||
|
||||
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
|
||||
to group expressions so that a failure in one group causes
|
||||
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
|
||||
expressions:
|
||||
|
||||
|
@ -62,7 +62,7 @@ be evaluated.
|
|||
|
||||
Notice that all the previous tests written in the simple
|
||||
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.
|
||||
|
||||
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
|
||||
maintain separate groups of tests for different parts of the
|
||||
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
|
||||
be displayed on a website to indicate service quality). For
|
||||
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}
|
||||
|
||||
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,
|
||||
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
|
||||
languages. That this is insufficient for all users is
|
||||
apparent if one considers the proliferation of ``simpler''
|
||||
testing frameworks in Racket such as SRFI-78, or the
|
||||
practice of beginner programmers. Unfortunately these
|
||||
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
|
||||
the testing style of all levels of programmer.
|
|
@ -1,7 +1,7 @@
|
|||
#lang scribble/doc
|
||||
@(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
|
||||
implements buggy versions of @racket[+] and @racket[-]
|
||||
|
@ -24,15 +24,15 @@ racket/base
|
|||
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
|
||||
tests. At the top of @tt{file-test.rkt} we import
|
||||
RktUnit and @tt{file.rkt}:
|
||||
RacUnit and @tt{file.rkt}:
|
||||
|
||||
@racketmod[
|
||||
racket/base
|
||||
|
||||
(require rktunit
|
||||
(require racunit
|
||||
"file.rkt")
|
||||
]
|
||||
|
||||
|
@ -43,7 +43,7 @@ Now we add some tests to check our library:
|
|||
(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.
|
||||
Here's the result I get:
|
||||
|
||||
|
@ -63,13 +63,13 @@ expected: 2
|
|||
The first @racket[#t] indicates the first test passed. The
|
||||
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
|
||||
to look at some features beyond the essentials.
|
||||
|
||||
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
|
||||
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
|
||||
cases. Here's a simple test case written using the
|
||||
@racket[test-begin] form:
|
||||
|
@ -91,7 +91,7 @@ Evalute this and you should see an error message like:
|
|||
A test
|
||||
... has a FAILURE
|
||||
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)
|
||||
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
|
||||
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
|
||||
will do for our example). In @tt{file-test.rkt} add the
|
||||
following lines:
|
||||
|
||||
@racketblock[
|
||||
(require rktunit/text-ui)
|
||||
(require racunit/text-ui)
|
||||
|
||||
(run-tests file-tests)
|
||||
]
|
||||
|
@ -161,6 +161,6 @@ following lines:
|
|||
Now evaluate the file and you should see similar output
|
||||
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
|
||||
defining your own checks. Have fun!
|
|
@ -1,12 +1,12 @@
|
|||
#lang scribble/doc
|
||||
@(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+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,
|
||||
from novices to experts.
|
||||
|
|
@ -12,7 +12,7 @@ There are also miscellaneous Scribble fixes.
|
|||
|
||||
@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
|
||||
underlying model, justifying incrementing the major version
|
||||
number. These changes are best explained in
|
|
@ -3,14 +3,14 @@
|
|||
|
||||
@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.
|
||||
|
||||
@section{Result Types}
|
||||
|
||||
@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
|
||||
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
|
||||
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
|
||||
in hash-monad.rkt and monad.rkt might be of interest for
|
||||
constructing user interfaces. The API is still in flux, so
|
|
@ -3,13 +3,13 @@
|
|||
|
||||
@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}
|
||||
|
||||
@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.
|
||||
|
||||
@defproc[(run-tests (test (or/c test-case? test-suite?))
|
||||
|
@ -33,15 +33,15 @@ information.
|
|||
|
||||
@section{Graphical User Interface}
|
||||
|
||||
@defmodule[rktunit/gui]
|
||||
@defmodule[racunit/gui]
|
||||
|
||||
RktUnit also provides a GUI test runner, available from the
|
||||
@racketmodname[rktunit/gui] module.
|
||||
RacUnit also provides a GUI test runner, available from the
|
||||
@racketmodname[racunit/gui] module.
|
||||
|
||||
@defproc[(test/gui [test (or/c test-case? test-suite?)] ...)
|
||||
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.
|
||||
|
||||
}
|
||||
|
@ -49,7 +49,7 @@ GUI is updated as tests complete.
|
|||
@defproc[(make-gui-runner)
|
||||
(-> (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.
|
||||
|
||||
}
|
|
@ -11,7 +11,7 @@
|
|||
;; CONSTANTS
|
||||
|
||||
(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)
|
||||
|
|
@ -1,3 +1,3 @@
|
|||
#lang racket
|
||||
(require rktunit/gui)
|
||||
(provide (all-from-out rktunit/gui))
|
||||
(require racunit/gui)
|
||||
(provide (all-from-out racunit/gui))
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
#lang racket
|
||||
(require rktunit)
|
||||
(provide (all-from-out rktunit))
|
||||
(require racunit)
|
||||
(provide (all-from-out racunit))
|
||||
|
|
|
@ -1,3 +1,3 @@
|
|||
#lang racket
|
||||
(require rktunit/text-ui)
|
||||
(provide (all-from-out rktunit/text-ui))
|
||||
(require racunit/text-ui)
|
||||
(provide (all-from-out racunit/text-ui))
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
racket/file
|
||||
racket/sandbox
|
||||
racket/promise
|
||||
mzlib/string
|
||||
racket/string
|
||||
(for-syntax racket/base))
|
||||
|
||||
(provide interaction
|
||||
|
@ -97,7 +97,12 @@
|
|||
(map
|
||||
(lambda (s)
|
||||
(car (format-output s error-color)))
|
||||
(filter
|
||||
(lambda (s) (not (equal? s "")))
|
||||
(let sloop ([s (caar val-list+outputs)])
|
||||
(apply
|
||||
append
|
||||
(map (lambda (s)
|
||||
(if ((string-length s) . > . maxlen)
|
||||
;; break the error message into multiple lines:
|
||||
(let loop ([pos (sub1 maxlen)])
|
||||
|
@ -108,7 +113,8 @@
|
|||
(cons (substring s 0 pos)
|
||||
(sloop (substring s (add1 pos))))]
|
||||
[else (loop (sub1 pos))]))
|
||||
(list s))))
|
||||
(list s)))
|
||||
(regexp-split #rx"\n" s))))))
|
||||
;; Normal result case:
|
||||
(let ([val-list (caar val-list+outputs)])
|
||||
(if (equal? val-list (list (void)))
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -4,57 +4,43 @@
|
|||
|
||||
@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[
|
||||
|
||||
@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
|
||||
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
|
||||
For example, if you have a program @filepath{take-over-world.rkt} and
|
||||
you'd like to compile it to bytecode, along with all of its
|
||||
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
|
||||
@exec{setup-plt} tool is described in @other-manual['(lib
|
||||
"scribblings/setup-plt/setup-plt.scrbl")].
|
||||
|
||||
@item{@exec{raco setup} manages a Racket installation, including
|
||||
manually installed packages.
|
||||
|
||||
For example, if you create your own library @techlink{collection}
|
||||
called @filepath{take-over}, and you'd like to build all bytecode and
|
||||
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}
|
||||
tool is described in @other-manual['(lib "planet/planet.scrbl")].
|
||||
|
||||
@item{@exec{raco planet} manages packages that are normally
|
||||
downloaded automatically, on demand.
|
||||
|
||||
For example, if you'd like to see a list of @|PLaneT| packages that
|
||||
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")].
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
#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 'rf "robby" "beverly hills park"))
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
#lang scheme
|
||||
(require rktunit rktunit/text-ui "2.ss")
|
||||
(require racunit racunit/text-ui "2.ss")
|
||||
|
||||
(define s0 (initialize (flat-contract integer?) =))
|
||||
(define s2 (push (push s0 2) 1))
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
#lang scheme
|
||||
(require rktunit rktunit/text-ui "3.ss")
|
||||
(require racunit racunit/text-ui "3.ss")
|
||||
|
||||
(define d0 (initialize (flat-contract integer?) =))
|
||||
(define d (put (put (put d0 'a 2) 'b 2) 'c 1))
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
#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))
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
|
||||
@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
|
||||
operations for grabbing and restoring portions of a computation.
|
||||
|
||||
|
@ -27,22 +27,22 @@ computation.
|
|||
(car 17)
|
||||
]
|
||||
|
||||
To catch an exception, use the @scheme[with-handlers] form:
|
||||
To catch an exception, use the @racket[with-handlers] form:
|
||||
|
||||
@specform[
|
||||
(with-handlers ([predicate-expr handler-expr] ...)
|
||||
body ...+)
|
||||
]{}
|
||||
|
||||
Each @scheme[_predicate-expr] in a handler determines a kind of
|
||||
exception that is caught by the @scheme[with-handlers] form, and the
|
||||
Each @racket[_predicate-expr] in a handler determines a kind of
|
||||
exception that is caught by the @racket[with-handlers] form, and the
|
||||
value representing the exception is passed to the handler procedure
|
||||
produced by @scheme[_handler-expr]. The result of the
|
||||
@scheme[_handler-expr] is the result of the @scheme[with-handlers]
|
||||
produced by @racket[_handler-expr]. The result of the
|
||||
@racket[_handler-expr] is the result of the @racket[with-handlers]
|
||||
expression.
|
||||
|
||||
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[
|
||||
(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))
|
||||
]
|
||||
|
||||
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
|
||||
@scheme[exn:fail] structure:
|
||||
@racket[exn:fail] structure:
|
||||
|
||||
@interaction[
|
||||
(error "crash!")
|
||||
|
@ -63,11 +63,11 @@ packages an error message and other information into an
|
|||
(error "crash!"))
|
||||
]
|
||||
|
||||
The @scheme[exn:fail:contract:divide-by-zero] and @scheme[exn:fail]
|
||||
structure types are sub-types of the @scheme[exn] structure
|
||||
The @racket[exn:fail:contract:divide-by-zero] and @racket[exn:fail]
|
||||
structure types are sub-types of the @racket[exn] structure
|
||||
type. Exceptions raised by core forms and functions always raise an
|
||||
instance of @scheme[exn] or one of its sub-types, but an exception
|
||||
does not have to be represented by a structure. The @scheme[raise]
|
||||
instance of @racket[exn] or one of its sub-types, but an exception
|
||||
does not have to be represented by a structure. The @racket[raise]
|
||||
function lets you raise any value as an exception:
|
||||
|
||||
@interaction[
|
||||
|
@ -78,7 +78,7 @@ function lets you raise any value as an exception:
|
|||
(/ 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
|
||||
predicates are tried in order, and if none of them match, then the
|
||||
exception is propagated to enclosing contexts.
|
||||
|
@ -95,7 +95,7 @@ exception is propagated to enclosing contexts.
|
|||
(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[
|
||||
(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
|
||||
types Ctl-C in a terminal window or clicks the @onscreen{Stop} button
|
||||
in DrScheme to interrupt a computation, then normally the
|
||||
@scheme[exn:break] exception should not be caught. To catch only
|
||||
exceptions that represent errors, use @scheme[exn:fail?] as the
|
||||
in DrRacket to interrupt a computation, then normally the
|
||||
@racket[exn:break] exception should not be caught. To catch only
|
||||
exceptions that represent errors, use @racket[exn:fail?] as the
|
||||
predicate:
|
||||
|
||||
@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}
|
||||
keep going after an error is printed? You might think that it's
|
||||
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.
|
||||
|
||||
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
|
||||
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
|
||||
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
|
||||
@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}.
|
||||
|
||||
@interaction[
|
||||
|
@ -165,13 +165,13 @@ enclosing prompt that has a given @tech{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.
|
||||
|
||||
@tech{Prompts} and @tech{aborts} look very much like exception
|
||||
handling and raising. Indeed, prompts and aborts are essentially a
|
||||
more primitive form of exceptions, and @scheme[with-handlers] and
|
||||
@scheme[raise] are implemented in terms of prompts and aborts. The
|
||||
more primitive form of exceptions, and @racket[with-handlers] and
|
||||
@racket[raise] are implemented in terms of prompts and aborts. The
|
||||
power of the more primitive forms is related to the word
|
||||
``continuation'' in the operator names, as we discuss in the next
|
||||
section.
|
||||
|
@ -182,7 +182,7 @@ section.
|
|||
|
||||
|
||||
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
|
||||
the current function call and running up to the nearest enclosing
|
||||
prompt. (Keep in mind that each @tech{REPL} interaction is implicitly
|
||||
|
@ -190,31 +190,31 @@ wrapped in a prompt.)
|
|||
|
||||
For example, in
|
||||
|
||||
@schemeblock[
|
||||
@racketblock[
|
||||
(+ 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
|
||||
changing @scheme[0] to grab the continuation before returning 0:
|
||||
changing @racket[0] to grab the continuation before returning 0:
|
||||
|
||||
@interaction[
|
||||
#:eval cc-eval
|
||||
(define saved-k #f)
|
||||
(define (save-it!)
|
||||
(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)
|
||||
0)))
|
||||
(+ 1 (+ 1 (+ 1 (save-it!))))
|
||||
]
|
||||
|
||||
The @tech{continuation} saved in @scheme[save-k] encapsulates the
|
||||
program context @scheme[(+ 1 (+ 1 (+ 1 _?)))], where @scheme[_?]
|
||||
The @tech{continuation} saved in @racket[save-k] encapsulates the
|
||||
program context @racket[(+ 1 (+ 1 (+ 1 _?)))], where @racket[_?]
|
||||
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
|
||||
function @scheme[(lambda (v) (+ 1 (+ 1 (+ 1 v))))]:
|
||||
function @racket[(lambda (v) (+ 1 (+ 1 (+ 1 v))))]:
|
||||
|
||||
@interaction[
|
||||
#:eval cc-eval
|
||||
|
@ -224,7 +224,7 @@ function @scheme[(lambda (v) (+ 1 (+ 1 (+ 1 v))))]:
|
|||
]
|
||||
|
||||
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
|
||||
|
||||
@interaction[
|
||||
|
@ -236,7 +236,7 @@ not syntactically. For example, with
|
|||
(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))))))]:
|
||||
|
||||
@interaction[
|
||||
|
@ -245,25 +245,25 @@ the continuation in @scheme[saved-k] becomes @scheme[(lambda (x) (+ 5
|
|||
(saved-k 10)
|
||||
]
|
||||
|
||||
A more traditional continuation operator in Scheme is
|
||||
@scheme[call-with-current-continuation], which is often abbreviated
|
||||
@scheme[call/cc]. It is like
|
||||
@scheme[call-with-composable-continuation], but applying the captured
|
||||
A more traditional continuation operator in Racket is
|
||||
@racket[call-with-current-continuation], which is often abbreviated
|
||||
@racket[call/cc]. It is like
|
||||
@racket[call-with-composable-continuation], but applying the captured
|
||||
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
|
||||
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
|
||||
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
|
||||
built-in @tech{abort}.
|
||||
|
||||
For an example of how @tech{continuations} are useful, see
|
||||
@other-manual['(lib "scribblings/more/more.scrbl")]. For specific
|
||||
control operators that have more convenient names than the primitives
|
||||
described here, see @schememodname[scheme/control].
|
||||
described here, see @racketmodname[racket/control].
|
||||
|
||||
@; ----------------------------------------------------------------------
|
||||
|
||||
|
|
|
@ -1,28 +1,26 @@
|
|||
#lang scribble/doc
|
||||
#lang scribble/base
|
||||
@(require scribble/manual
|
||||
"guide-utils.ss")
|
||||
|
||||
@(define r6rs @elem{R@superscript{6}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
|
||||
there are many others. Indeed, ``Scheme'' is perhaps more of an idea
|
||||
than a specific language.
|
||||
We use ``Racket'' to refer to a specific dialect of the Lisp language,
|
||||
and one that is based on the Scheme branch of the Lisp family.
|
||||
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
|
||||
Scheme, 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[] (or another PLT Scheme module form) do not
|
||||
work with the default mode of most PLT Scheme tools.
|
||||
|
||||
``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.
|
||||
``Racket'' is not, however, the only dialect of Lisp that is supported
|
||||
by Racket tools. On the contrary, Racket tools are designed to support
|
||||
multiple dialects of Lisp and even multiple languages, which allows
|
||||
the Racket tool suite to serve multiple communities. Racket also gives
|
||||
programmers and researchers the tools they need to explore and create
|
||||
new languages.
|
||||
|
||||
@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
|
||||
it is currently the most widely implemented Scheme standard.
|
||||
|
||||
PLT Scheme tools in their default modes do not conform to @|r5rs|,
|
||||
mainly because PLT Scheme tools generally expect modules, and @|r5rs|
|
||||
Racket tools in their default modes do not conform to @|r5rs|,
|
||||
mainly because Racket tools generally expect modules, and @|r5rs|
|
||||
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
|
||||
systems do not recognize @scheme[@#,hash-lang[]
|
||||
@#,schememodname[r5rs]]. The @exec{plt-r5rs} executable (see
|
||||
|
@ -50,106 +48,106 @@ systems do not recognize @scheme[@#,hash-lang[]
|
|||
conforms to the @|r5rs| standard.
|
||||
|
||||
Aside from the module system, the syntactic forms and functions of
|
||||
@|r5rs| and PLT Scheme differ. Only simple @|r5rs| become PLT Scheme
|
||||
programs when prefixed with @scheme[@#,hash-lang[] scheme], and
|
||||
relatively few PLT Scheme programs become @|r5rs| programs when a
|
||||
@|r5rs| and Racket differ. Only simple @|r5rs| become Racket
|
||||
programs when prefixed with @scheme[@#,hash-lang[] racket], and
|
||||
relatively few Racket programs become @|r5rs| programs when a
|
||||
@hash-lang[] line is removed. Also, when mixing ``@|r5rs| modules''
|
||||
with PLT Scheme modules, beware that @|r5rs| pairs correspond to PLT
|
||||
Scheme mutable pairs (as constructed with @scheme[mcons]).
|
||||
with Racket modules, beware that @|r5rs| pairs correspond to
|
||||
Racket mutable pairs (as constructed with @scheme[mcons]).
|
||||
|
||||
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|}
|
||||
|
||||
``@|r6rs|'' stands for @link["../r6rs-std/index.html"]{The
|
||||
Revised@superscript{6} Report on the Algorithmic Language Scheme},
|
||||
which extends @|r5rs| with a module system that is similar to the PLT
|
||||
Scheme module system.
|
||||
which extends @|r5rs| with a module system that is similar to the
|
||||
Racket module system.
|
||||
|
||||
When an @|r6rs| library or top-level program is prefixed with
|
||||
@schememetafont{#!}@schememodname[r6rs] (which is valid @|r6rs|
|
||||
syntax), then it can also be used as a PLT Scheme program. This works
|
||||
because @schememetafont{#!} in PLT Scheme is treated as a shorthand
|
||||
syntax), then it can also be used as a Racket program. This works
|
||||
because @schememetafont{#!} in Racket is treated as a shorthand
|
||||
for @hash-lang[] followed by a space, so
|
||||
@schememetafont{#!}@schememodname[r6rs] selects the
|
||||
@schememodname[r6rs] module language. As with @|r5rs|, however, beware
|
||||
that the syntactic forms and functions of @|r6rs| differ from PLT
|
||||
Scheme, and @|r6rs| pairs are mutable pairs.
|
||||
that the syntactic forms and functions of @|r6rs| differ from
|
||||
Racket, and @|r6rs| pairs are mutable pairs.
|
||||
|
||||
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
|
||||
extend a base language (as described in @secref["macros"]), but macros
|
||||
and alternate parsers can construct an entirely new language from the
|
||||
ground up.
|
||||
|
||||
The @hash-lang[] line that starts a PLT Scheme module declares the
|
||||
base language of the module. By ``PLT Scheme,'' we usually mean
|
||||
@hash-lang[] followed by the base language @schememodname[scheme] or
|
||||
@schememodname[scheme/base] (of which @schememodname[scheme] is an
|
||||
extension). The PLT Scheme distribution provides additional languages,
|
||||
The @hash-lang[] line that starts a Racket module declares the
|
||||
base language of the module. By ``Racket,'' we usually mean
|
||||
@hash-lang[] followed by the base language @racketmodname[racket] or
|
||||
@racketmodname[racket/base] (of which @racketmodname[racket] is an
|
||||
extension). The Racket distribution provides additional languages,
|
||||
including the following:
|
||||
|
||||
@itemize[
|
||||
|
||||
@item{@schememodname[typed/scheme] --- like
|
||||
@schememodname[scheme], but statically typed; see
|
||||
@item{@racketmodname[typed/scheme] --- like
|
||||
@racketmodname[racket], but statically typed; see
|
||||
@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
|
||||
@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
|
||||
@other-manual['(lib "frtime/scribblings/frtime.scrbl")]}
|
||||
|
||||
@item{@schememodname[scribble/doc] --- a language, which looks more
|
||||
like Latex than Scheme, for writing documentation; see
|
||||
@item{@racketmodname[scribble/base] --- a language, which looks more
|
||||
like Latex than Racket, for writing documentation; see
|
||||
@other-manual['(lib "scribblings/scribble/scribble.scrbl")]}
|
||||
|
||||
]
|
||||
|
||||
Each of these languages is used by starting module with the language
|
||||
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
|
||||
@schemeidfont{/lang/reader}. For example, the language name
|
||||
@schememodname[scribble/doc] is expanded to
|
||||
@scheme[scribble/doc/lang/reader], which is the module that implements
|
||||
@racketidfont{/lang/reader}. For example, the language name
|
||||
@racketmodname[scribble/doc] is expanded to
|
||||
@racket[scribble/doc/lang/reader], which is the module that implements
|
||||
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.
|
||||
|
||||
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
|
||||
@schememodname[s-exp] for the language's syntactic forms. Thus,
|
||||
@scheme[@#,hash-lang[] @#,schememodname[s-exp] "mylang.ss"] parses
|
||||
the module body using the normal PLT Scheme reader, by then imports
|
||||
@racketmodname[s-exp] for the language's syntactic forms. Thus,
|
||||
@racket[@#,hash-lang[] @#,racketmodname[s-exp] "mylang.rkt"] parses
|
||||
the module body using the normal Racket reader, by then imports
|
||||
the initial syntax and functions for the module body from
|
||||
@scheme["mylang.ss"]. Similarly, @scheme[@#,hash-lang[]
|
||||
@#,schememodname[planet] _planet-path] loads a language via
|
||||
@racket["mylang.rkt"]. Similarly, @racket[@#,hash-lang[]
|
||||
@#,racketmodname[planet] _planet-path] loads a language via
|
||||
@seclink["top" #:doc '(lib "planet/planet.scrbl")]{@|PLaneT|}.
|
||||
|
||||
@; --------------------------------------------------
|
||||
|
||||
@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.
|
||||
The languages are documented in @other-manual['(lib
|
||||
"scribblings/htdp-langs/htdp-langs.scrbl")].
|
||||
|
||||
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.
|
||||
|
|
|
@ -5,24 +5,24 @@
|
|||
|
||||
@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
|
||||
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
|
||||
now, the syntax of @scheme[for] is
|
||||
now, the syntax of @racket[for] is
|
||||
|
||||
@specform[
|
||||
(for ([id sequence-expr] ...)
|
||||
body ...+)
|
||||
]{}
|
||||
|
||||
A @scheme[for] loop iterates through the sequence produced by the
|
||||
@scheme[_sequence-expr]. For each element of the sequence,
|
||||
@scheme[for] binds the element to @scheme[_id], and then it evaluates
|
||||
the @scheme[_body]s for side effects.
|
||||
A @racket[for] loop iterates through the sequence produced by the
|
||||
@racket[_sequence-expr]. For each element of the sequence,
|
||||
@racket[for] binds the element to @racket[_id], and then it evaluates
|
||||
the @racket[_body]s for side effects.
|
||||
|
||||
@examples[
|
||||
(for ([i '(1 2 3)])
|
||||
|
@ -31,10 +31,10 @@ the @scheme[_body]s for side effects.
|
|||
(printf "~a..." i))
|
||||
]
|
||||
|
||||
The @scheme[for/list] variant of @scheme[for] is more Scheme-like. It
|
||||
accumulates @scheme[_body] results into a list, instead of
|
||||
evaluating @scheme[_body] only for side effects. In more
|
||||
technical terms, @scheme[for/list] implements a @defterm{list
|
||||
The @racket[for/list] variant of @racket[for] is more Racket-like. It
|
||||
accumulates @racket[_body] results into a list, instead of
|
||||
evaluating @racket[_body] only for side effects. In more
|
||||
technical terms, @racket[for/list] implements a @defterm{list
|
||||
comprehension}.
|
||||
|
||||
@examples[
|
||||
|
@ -44,22 +44,22 @@ comprehension}.
|
|||
i)
|
||||
]
|
||||
|
||||
The full syntax of @scheme[for] accommodates multiple sequences to
|
||||
iterate in parallel, and the @scheme[for*] variant nests the
|
||||
The full syntax of @racket[for] accommodates multiple sequences to
|
||||
iterate in parallel, and the @racket[for*] variant nests the
|
||||
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
|
||||
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.
|
||||
|
||||
@section[#:tag "sequences"]{Sequence Constructors}
|
||||
|
||||
The @scheme[in-range] function generates a sequence of numbers, given
|
||||
an optional starting number (which defaults to @scheme[0]), a number
|
||||
The @racket[in-range] function generates a sequence of numbers, given
|
||||
an optional starting number (which defaults to @racket[0]), a number
|
||||
before which the sequences ends, and an optional step (which defaults
|
||||
to @scheme[1]).
|
||||
to @racket[1]).
|
||||
|
||||
@examples[
|
||||
(for ([i (in-range 3)])
|
||||
|
@ -74,10 +74,10 @@ to @scheme[1]).
|
|||
(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
|
||||
to @scheme[0]), the step is always @scheme[1], and there is no upper
|
||||
limit. A @scheme[for] loop using just @scheme[in-naturals] will never
|
||||
to @racket[0]), the step is always @racket[1], and there is no upper
|
||||
limit. A @racket[for] loop using just @racket[in-naturals] will never
|
||||
terminate unless a body expression raises an exception or otherwise
|
||||
escapes.
|
||||
|
||||
|
@ -88,7 +88,7 @@ escapes.
|
|||
(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
|
||||
like the given sequence, but truncated either immediately before or
|
||||
immediately after the first element for which the predicate returns
|
||||
|
@ -100,8 +100,8 @@ true.
|
|||
(display i))
|
||||
]
|
||||
|
||||
Sequence constructors like @scheme[in-list], @scheme[in-vector] and
|
||||
@scheme[in-string] simply make explicit the use of a list, vector, or
|
||||
Sequence constructors like @racket[in-list], @racket[in-vector] and
|
||||
@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
|
||||
wrong kind of value, and since they otherwise avoid a run-time
|
||||
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}
|
||||
|
||||
@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[
|
||||
(for (clause ...)
|
||||
|
@ -127,8 +127,8 @@ A more complete syntax of @scheme[for] is
|
|||
(code:line #:when boolean-expr)])
|
||||
]{}
|
||||
|
||||
When multiple @scheme[[_id _sequence-expr]] clauses are provided
|
||||
in a @scheme[for] form, the corresponding sequences are traversed in
|
||||
When multiple @racket[[_id _sequence-expr]] clauses are provided
|
||||
in a @racket[for] form, the corresponding sequences are traversed in
|
||||
parallel:
|
||||
|
||||
@interaction[
|
||||
|
@ -137,8 +137,8 @@ parallel:
|
|||
(printf "Chapter ~a. ~a\n" i chapter))
|
||||
]
|
||||
|
||||
With parallel sequences, the @scheme[for] expression stops iterating
|
||||
when any sequence ends. This behavior allows @scheme[in-naturals],
|
||||
With parallel sequences, the @racket[for] expression stops iterating
|
||||
when any sequence ends. This behavior allows @racket[in-naturals],
|
||||
which creates an infinite sequence of numbers, to be used for
|
||||
indexing:
|
||||
|
||||
|
@ -148,7 +148,7 @@ indexing:
|
|||
(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:
|
||||
|
||||
@interaction[
|
||||
|
@ -157,12 +157,12 @@ nests multiple sequences instead of running them in parallel:
|
|||
(printf "~a ~a\n" book chapter))
|
||||
]
|
||||
|
||||
Thus, @scheme[for*] is a shorthand for nested @scheme[for]s in the
|
||||
same way that @scheme[let*] is a shorthand for nested @scheme[let]s.
|
||||
Thus, @racket[for*] is a shorthand for nested @racket[for]s in the
|
||||
same way that @racket[let*] is a shorthand for nested @racket[let]s.
|
||||
|
||||
The @scheme[#:when _boolean-expr] form of a @scheme[_clause] is
|
||||
another shorthand. It allows the @scheme[_body]s to evaluate only
|
||||
when the @scheme[_boolean-expr] produces a true value:
|
||||
The @racket[#:when _boolean-expr] form of a @racket[_clause] is
|
||||
another shorthand. It allows the @racket[_body]s to evaluate only
|
||||
when the @racket[_boolean-expr] produces a true value:
|
||||
|
||||
@interaction[
|
||||
(for* ([book '("Guide" "Reference")]
|
||||
|
@ -171,11 +171,11 @@ when the @scheme[_boolean-expr] produces a true value:
|
|||
(printf "~a ~a\n" book chapter))
|
||||
]
|
||||
|
||||
A @scheme[_boolean-expr] with @scheme[#:when] can refer to any of the
|
||||
preceding iteration bindings. In a @scheme[for] form, this scoping
|
||||
A @racket[_boolean-expr] with @racket[#:when] can refer to any of the
|
||||
preceding iteration bindings. In a @racket[for] form, this scoping
|
||||
makes sense only if the test is nested in the iteration of the
|
||||
preceding bindings; thus, bindings separated by @scheme[#:when] are
|
||||
mutually nested, instead of in parallel, even with @scheme[for].
|
||||
preceding bindings; thus, bindings separated by @racket[#:when] are
|
||||
mutually nested, instead of in parallel, even with @racket[for].
|
||||
|
||||
@interaction[
|
||||
(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))
|
||||
]
|
||||
|
||||
@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],
|
||||
evaluates the @scheme[_body]s to obtain values that go into a
|
||||
The @racket[for/list] form, which has the same syntax as @racket[for],
|
||||
evaluates the @racket[_body]s to obtain values that go into a
|
||||
newly constructed list:
|
||||
|
||||
@interaction[
|
||||
|
@ -198,8 +198,8 @@ newly constructed list:
|
|||
(string-append (number->string i) ". " chapter))
|
||||
]
|
||||
|
||||
A @scheme[#:when] clause in a @scheme[for-list] form prunes the result
|
||||
list along with evaluations of the @scheme[_body]s:
|
||||
A @racket[#:when] clause in a @racket[for-list] form prunes the result
|
||||
list along with evaluations of the @racket[_body]s:
|
||||
|
||||
@interaction[
|
||||
(for/list ([i (in-naturals 1)]
|
||||
|
@ -208,13 +208,13 @@ list along with evaluations of the @scheme[_body]s:
|
|||
chapter)
|
||||
]
|
||||
|
||||
This pruning behavior of @scheme[#:when] is more useful with
|
||||
@scheme[for/list] than @scheme[for]. Whereas a plain @scheme[when]
|
||||
form normally suffices with @scheme[for], a @scheme[when] expression
|
||||
form in a @scheme[for/list] would cause the result list to contain
|
||||
This pruning behavior of @racket[#:when] is more useful with
|
||||
@racket[for/list] than @racket[for]. Whereas a plain @racket[when]
|
||||
form normally suffices with @racket[for], a @racket[when] expression
|
||||
form in a @racket[for/list] would cause the result list to contain
|
||||
@|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:
|
||||
|
||||
@interaction[
|
||||
|
@ -223,23 +223,23 @@ iterations:
|
|||
(string-append book " " chapter))
|
||||
]
|
||||
|
||||
A @scheme[for*/list] form is not quite the same thing as nested
|
||||
@scheme[for/list] forms. Nested @scheme[for/list]s would produce a
|
||||
A @racket[for*/list] form is not quite the same thing as nested
|
||||
@racket[for/list] forms. Nested @racket[for/list]s would produce a
|
||||
list of lists, instead of one flattened list. Much like
|
||||
@scheme[#:when], then, the nesting of @scheme[for*/list] is more
|
||||
useful than the nesting of @scheme[for*].
|
||||
@racket[#:when], then, the nesting of @racket[for*/list] is more
|
||||
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
|
||||
@scheme[and], stopping as soon as it encounters @scheme[#f]:
|
||||
The @racket[for/and] form combines iteration results with
|
||||
@racket[and], stopping as soon as it encounters @racket[#f]:
|
||||
|
||||
@interaction[
|
||||
(for/and ([chapter '("Intro" "Details" "Conclusion")])
|
||||
(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:
|
||||
|
||||
@interaction[
|
||||
|
@ -247,14 +247,14 @@ stopping as soon as it encounters a true value:
|
|||
(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.
|
||||
|
||||
@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 @scheme[_body]s are evaluated, skipping further iterations.
|
||||
This form is most useful with a @scheme[#:when] clause.
|
||||
The @racket[for/first] form returns the result of the first time that
|
||||
the @racket[_body]s are evaluated, skipping further iterations.
|
||||
This form is most useful with a @racket[#:when] clause.
|
||||
|
||||
@interaction[
|
||||
(for/first ([chapter '("Intro" "Details" "Conclusion" "Index")]
|
||||
|
@ -262,11 +262,11 @@ This form is most useful with a @scheme[#:when] clause.
|
|||
chapter)
|
||||
]
|
||||
|
||||
If the @scheme[_body]s are evaluated zero times, then the result
|
||||
is @scheme[#f].
|
||||
If the @racket[_body]s are evaluated zero times, then the result
|
||||
is @racket[#f].
|
||||
|
||||
The @scheme[for/last] form runs all iterations, returning the value of
|
||||
the last iteration (or @scheme[#f] if no iterations are run):
|
||||
The @racket[for/last] form runs all iterations, returning the value of
|
||||
the last iteration (or @racket[#f] if no iterations are run):
|
||||
|
||||
@interaction[
|
||||
(for/last ([chapter '("Intro" "Details" "Conclusion" "Index")]
|
||||
|
@ -274,7 +274,7 @@ the last iteration (or @scheme[#f] if no iterations are run):
|
|||
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:
|
||||
|
||||
@interaction[
|
||||
|
@ -289,26 +289,26 @@ the same facility with nested iterations:
|
|||
(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
|
||||
@scheme[for], because accumulation variables must be declared at the
|
||||
@racket[for], because accumulation variables must be declared at the
|
||||
beginning:
|
||||
|
||||
@schemeblock[
|
||||
@racketblock[
|
||||
(for/fold ([_accum-id _init-expr] ...)
|
||||
(_clause ...)
|
||||
_body ...+)
|
||||
]
|
||||
|
||||
In the simple case, only one @scheme[[_accum-id _init-expr]] is
|
||||
provided, and the result of the @scheme[for/fold] is the final value
|
||||
for @scheme[_accum-id], which starts out with the value of
|
||||
@scheme[_init-expr]. In the @scheme[_clause]s and
|
||||
@scheme[_body]s, @scheme[_accum-id] can be referenced to get its
|
||||
current value, and the last @scheme[_body] provides the value of
|
||||
@scheme[_accum-id] for the next iteration.
|
||||
In the simple case, only one @racket[[_accum-id _init-expr]] is
|
||||
provided, and the result of the @racket[for/fold] is the final value
|
||||
for @racket[_accum-id], which starts out with the value of
|
||||
@racket[_init-expr]. In the @racket[_clause]s and
|
||||
@racket[_body]s, @racket[_accum-id] can be referenced to get its
|
||||
current value, and the last @racket[_body] provides the value of
|
||||
@racket[_accum-id] for the next iteration.
|
||||
|
||||
@examples[
|
||||
(for/fold ([len 0])
|
||||
|
@ -322,9 +322,9 @@ current value, and the last @scheme[_body] provides the value of
|
|||
chapter)
|
||||
]
|
||||
|
||||
When multiple @scheme[_accum-id]s are specified, then the last
|
||||
@scheme[_body] must produce multiple values, one for each
|
||||
@scheme[_accum-id]. The @scheme[for/fold] expression itself produces
|
||||
When multiple @racket[_accum-id]s are specified, then the last
|
||||
@racket[_body] must produce multiple values, one for each
|
||||
@racket[_accum-id]. The @racket[for/fold] expression itself produces
|
||||
multiple values for the results.
|
||||
|
||||
@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
|
||||
values for each iteration: a key and a value.
|
||||
|
||||
In the same way that @scheme[let-values] binds multiple results to
|
||||
multiple identifiers, @scheme[for] can bind multiple sequence elements
|
||||
In the same way that @racket[let-values] binds multiple results to
|
||||
multiple identifiers, @racket[for] can bind multiple sequence elements
|
||||
to multiple iteration identifiers:
|
||||
|
||||
@margin-note{While @scheme[let] must be changed to @scheme[let-values]
|
||||
to bind multiple identifier, @scheme[for] simply allows a
|
||||
@margin-note{While @racket[let] must be changed to @racket[let-values]
|
||||
to bind multiple identifier, @racket[for] simply allows a
|
||||
parenthesized list of identifiers instead of a single
|
||||
identifier in any clause.}
|
||||
|
||||
|
@ -358,8 +358,8 @@ to multiple iteration identifiers:
|
|||
(printf "~a count: ~a\n" k v))
|
||||
]
|
||||
|
||||
This extension to multiple-value bindings works for all @scheme[for]
|
||||
variants. For example, @scheme[for*/list] nests iterations, builds a
|
||||
This extension to multiple-value bindings works for all @racket[for]
|
||||
variants. For example, @racket[for*/list] nests iterations, builds a
|
||||
list, and also works with multiple-valued sequences:
|
||||
|
||||
@interaction[
|
||||
|
@ -371,26 +371,26 @@ list, and also works with multiple-valued sequences:
|
|||
|
||||
@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
|
||||
loop, however, is normally specific to a particular kind of data, such
|
||||
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.
|
||||
|
||||
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
|
||||
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]
|
||||
[(id) fast-seq]
|
||||
[(id id) fast-indexed-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]
|
||||
fast-seq (in-range expr expr)
|
||||
(in-range expr expr expr)
|
||||
|
@ -405,14 +405,14 @@ fast-seq (in-range expr expr)
|
|||
(stop-after fast-seq predicate-expr)
|
||||
]
|
||||
|
||||
@schemegrammar[
|
||||
@racketgrammar[
|
||||
#:literals [in-indexed stop-before stop-after]
|
||||
fast-indexed-seq (in-indexed fast-seq)
|
||||
(stop-before fast-indexed-seq predicate-expr)
|
||||
(stop-after fast-indexed-seq predicate-expr)
|
||||
]
|
||||
|
||||
@schemegrammar[
|
||||
@racketgrammar[
|
||||
#:literals [in-parallel stop-before stop-after]
|
||||
fast-parallel-seq (in-parallel fast-seq ...)
|
||||
(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
|
||||
set of sequence values. The documentation for a sequence constructor
|
||||
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}
|
||||
|
|
|
@ -4,22 +4,24 @@
|
|||
scribble/eval
|
||||
mzlib/process
|
||||
"guide-utils.ss"
|
||||
(for-label scheme/tcp
|
||||
scheme/serialize
|
||||
scheme/port))
|
||||
(for-label racket/tcp
|
||||
racket/serialize
|
||||
racket/port))
|
||||
|
||||
@(define io-eval (make-base-eval))
|
||||
|
||||
@(define (twocolumn a b)
|
||||
@(define (threecolumn a b c)
|
||||
(make-table #f
|
||||
(list (list (make-flow (list a))
|
||||
(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))
|
||||
|
||||
@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
|
||||
specifically, an @defterm{input port} represents a stream from which a
|
||||
program can read data, and an @defterm{output port} represents a
|
||||
|
@ -28,7 +30,7 @@ stream for writing data.
|
|||
@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
|
||||
examples:
|
||||
|
@ -36,8 +38,8 @@ examples:
|
|||
@itemize[
|
||||
|
||||
@;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
@item{@bold{Files:} The @scheme[open-output-file] function opens a
|
||||
file for writing, and @scheme[open-input-file] opens a file for
|
||||
@item{@bold{Files:} The @racket[open-output-file] function opens a
|
||||
file for writing, and @racket[open-input-file] opens a file for
|
||||
reading.
|
||||
|
||||
@(interaction-eval #:eval io-eval (define old-dir (current-directory)))
|
||||
|
@ -54,9 +56,9 @@ examples:
|
|||
(close-input-port in)
|
||||
]
|
||||
|
||||
If a file exists already, then @scheme[open-output-file] raises an
|
||||
exception by default. Supply an option like @scheme[#:exists
|
||||
'truncate] or @scheme[#:exists 'update] to re-write or update the
|
||||
If a file exists already, then @racket[open-output-file] raises an
|
||||
exception by default. Supply an option like @racket[#:exists
|
||||
'truncate] or @racket[#:exists 'update] to re-write or update the
|
||||
file:
|
||||
|
||||
@examples[
|
||||
|
@ -66,9 +68,9 @@ file:
|
|||
(close-output-port out)
|
||||
]
|
||||
|
||||
Instead of having to match @scheme[open-input-file] and
|
||||
@scheme[open-output-file] calls, most Scheme programmers will instead
|
||||
use @scheme[call-with-output-file], which takes a function to call
|
||||
Instead of having to match @racket[open-input-file] and
|
||||
@racket[open-output-file] calls, most Racket programmers will instead
|
||||
use @racket[call-with-output-file], which takes a function to call
|
||||
with the output port; when the function returns, the port is closed.
|
||||
|
||||
@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))}
|
||||
|
||||
@;- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
@item{@bold{Strings:} The @scheme[open-output-string] function creates
|
||||
a port that accumulates data into a string, and @scheme[get-output-string]
|
||||
extracts the accumulated string. The @scheme[open-input-string] function
|
||||
@item{@bold{Strings:} The @racket[open-output-string] function creates
|
||||
a port that accumulates data into a string, and @racket[get-output-string]
|
||||
extracts the accumulated string. The @racket[open-input-string] function
|
||||
creates a port to read from a string.
|
||||
|
||||
@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
|
||||
a TCP communication. The @scheme[tcp-listen] function creates a
|
||||
server, which accepts connections via @scheme[tcp-accept].
|
||||
a TCP communication. The @racket[tcp-listen] function creates a
|
||||
server, which accepts connections via @racket[tcp-accept].
|
||||
|
||||
@examples[
|
||||
#: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
|
||||
subprocess's stdin, stdout, and stderr. (The first three arguments
|
||||
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
|
||||
Scheme, and not related to OS-level pipes for communicating between
|
||||
Racket, and not related to OS-level pipes for communicating between
|
||||
different processes.
|
||||
|
||||
@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
|
||||
argument, and the default is the @defterm{current input port} or
|
||||
@defterm{current output port}. Furthermore, error messages are written
|
||||
to the @defterm{current error port}, which is an output port. The
|
||||
@scheme[current-input-port], @scheme[current-output-port], and
|
||||
@scheme[current-error-port] functions return the corresponding current
|
||||
@racket[current-input-port], @racket[current-output-port], and
|
||||
@racket[current-error-port] functions return the corresponding current
|
||||
ports.
|
||||
|
||||
@examples[
|
||||
|
@ -175,7 +177,7 @@ ports.
|
|||
(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
|
||||
terminal. More generally, they are connected to the OS-level stdin,
|
||||
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)
|
||||
]
|
||||
|
||||
The current-port functions are actually parameters, which means that
|
||||
their values can be set with @scheme[parameterize].
|
||||
The current-port functions are actually @tech{parameters}, which means
|
||||
that their values can be set with @racket[parameterize].
|
||||
|
||||
@margin-note{See @secref["parameterize"] for an introduction to parameters.}
|
||||
|
||||
@examples[
|
||||
#: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:
|
||||
|
||||
@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 }
|
||||
|
||||
@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
|
||||
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:
|
||||
|
||||
@twocolumn[
|
||||
@threecolumn[
|
||||
|
||||
@interaction[
|
||||
(print 1/2)
|
||||
(print #\x)
|
||||
(print "hello")
|
||||
(print #"goodbye")
|
||||
(print '|pea pod|)
|
||||
(print '("i" pod))
|
||||
(print write)
|
||||
]
|
||||
|
||||
@interaction[
|
||||
(write 1/2)
|
||||
(write #\x)
|
||||
(write "hello")
|
||||
(write #"goodbye")
|
||||
(write '|dollar sign|)
|
||||
(write '("alphabet" soup))
|
||||
(write '|pea pod|)
|
||||
(write '("i" pod))
|
||||
(write write)
|
||||
]
|
||||
|
||||
|
@ -238,27 +255,35 @@ Here are some examples using each:
|
|||
(display #\x)
|
||||
(display "hello")
|
||||
(display #"goodbye")
|
||||
(display '|dollar sign|)
|
||||
(display '("alphabet" soup))
|
||||
(display '|pea pod|)
|
||||
(display '("i" pod))
|
||||
(display write)
|
||||
]
|
||||
|
||||
]
|
||||
|
||||
The @scheme[printf] function supports simple formatting of data and
|
||||
text. In the format string supplied to @scheme[printf], @litchar{~a}
|
||||
@scheme[display]s the next argument, while @litchar{~s}
|
||||
@scheme[write]s the next argument.
|
||||
Overall, @racket[print] as corresponds to the expression layer of
|
||||
Racket syntax, @racket[write] corresponds to the reader layer, and
|
||||
@racket[display] roughly corresponds to the character layer.
|
||||
|
||||
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[
|
||||
#:eval io-eval
|
||||
(define (deliver who what)
|
||||
(printf "Value for ~a: ~s" who what))
|
||||
(deliver "John" "string")
|
||||
(define (deliver who when what)
|
||||
(printf "Items ~a for shopper ~s: ~v" who when what))
|
||||
(deliver '("list") '("John") '("milk"))
|
||||
]
|
||||
|
||||
An advantage of @scheme[write], as opposed to @scheme[display], is
|
||||
that many forms of data can be read back in using @scheme[read].
|
||||
After using @racket[write], as opposed to @racket[display] or
|
||||
@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[
|
||||
#:eval io-eval
|
||||
|
@ -269,6 +294,8 @@ that many forms of data can be read back in using @scheme[read].
|
|||
(read in)
|
||||
(write #hash((a . "apple") (b . "banana")) out)
|
||||
(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)
|
||||
]
|
||||
|
||||
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
|
||||
@scheme[write] either using @schemeresultfont{#<....>} notation (for
|
||||
opaque structure types) or using @schemeresultfont{#(....)} vector
|
||||
@racket[write] either using @racketresultfont{#<....>} notation (for
|
||||
opaque structure types) or using @racketresultfont{#(....)} vector
|
||||
notation (for transparent structure types). In neither can can the
|
||||
result be read back in as an instance of the structure type:
|
||||
|
||||
@interaction[
|
||||
(define-struct posn (x y))
|
||||
(write (make-posn 1 2))
|
||||
(struct posn (x y))
|
||||
(write (posn 1 2))
|
||||
(define-values (in out) (make-pipe))
|
||||
(write (make-posn 1 2) out)
|
||||
(write (posn 1 2) out)
|
||||
(read in)
|
||||
]
|
||||
|
||||
@interaction[
|
||||
(define-struct posn (x y) #:transparent)
|
||||
(write (make-posn 1 2))
|
||||
(struct posn (x y) #:transparent)
|
||||
(write (posn 1 2))
|
||||
(define-values (in out) (make-pipe))
|
||||
(write (make-posn 1 2) out)
|
||||
(write (posn 1 2) out)
|
||||
(define v (read in))
|
||||
v
|
||||
(posn? v)
|
||||
(vector? v)
|
||||
]
|
||||
|
||||
The @scheme[define-serializable-struct] form defines a structure type
|
||||
that can be @scheme[serialize]d to a value that can be printed using
|
||||
@scheme[write] and restored via @scheme[read]. The @scheme[serialize]d
|
||||
result can be @scheme[deserialize]d to get back an instance of the
|
||||
The @racket[serializable-struct] form defines a structure type
|
||||
that can be @racket[serialize]d to a value that can be printed using
|
||||
@racket[write] and restored via @racket[read]. The @racket[serialize]d
|
||||
result can be @racket[deserialize]d to get back an instance of the
|
||||
original structure type. The serialization form and functions are
|
||||
provided by the @schememodname[scheme/serialize] library.
|
||||
provided by the @racketmodname[racket/serialize] library.
|
||||
|
||||
@examples[
|
||||
(require scheme/serialize)
|
||||
(define-serializable-struct posn (x y) #:transparent)
|
||||
(deserialize (serialize (make-posn 1 2)))
|
||||
(write (serialize (make-posn 1 2)))
|
||||
(require racket/serialize)
|
||||
(serializable-struct posn (x y) #:transparent)
|
||||
(deserialize (serialize (posn 1 2)))
|
||||
(write (serialize (posn 1 2)))
|
||||
(define-values (in out) (make-pipe))
|
||||
(write (serialize (make-posn 1 2)) out)
|
||||
(write (serialize (posn 1 2)) out)
|
||||
(deserialize (read in))
|
||||
]
|
||||
|
||||
In addition to the names bound by @scheme[define-struct],
|
||||
@scheme[define-serializable-struct] binds an identifier with
|
||||
deserialization information, and it automatically @scheme[provide]s
|
||||
the deserialization identifier from a module context. This
|
||||
deserialization identifier is accessed reflectively when a value is
|
||||
deserialized.
|
||||
In addition to the names bound by @racket[struct],
|
||||
@racket[serializable-struct] binds an identifier with deserialization
|
||||
information, and it automatically @racket[provide]s the
|
||||
deserialization identifier from a module context. This deserialization
|
||||
identifier is accessed reflectively when a value is deserialized.
|
||||
|
||||
@; ----------------------------------------------------------------------
|
||||
@section{Bytes, Characters, and Encodings}
|
||||
@section[#:tag "encodings"]{Bytes, Characters, and Encodings}
|
||||
|
||||
Functions like @scheme[read-line], @scheme[read], @scheme[display],
|
||||
and @scheme[write] all work in terms of @tech{characters} (which
|
||||
Functions like @racket[read-line], @racket[read], @racket[display],
|
||||
and @racket[write] all work in terms of @tech{characters} (which
|
||||
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
|
||||
@tech{characters}. The functions @scheme[read-byte] and
|
||||
@scheme[write-byte] read and write raw bytes. Other functions, such as
|
||||
@scheme[read-bytes-line], build on top of byte operations instead of
|
||||
@tech{characters}. The functions @racket[read-byte] and
|
||||
@racket[write-byte] read and write raw bytes. Other functions, such as
|
||||
@racket[read-bytes-line], build on top of byte operations instead of
|
||||
character operations.
|
||||
|
||||
In fact, the @scheme[read-char] and @scheme[write-char] functions are
|
||||
conceptually implemented in terms of @scheme[read-byte] and
|
||||
@scheme[write-byte]. When a single byte's value is less than 128, then
|
||||
In fact, the @racket[read-char] and @racket[write-char] functions are
|
||||
conceptually implemented in terms of @racket[read-byte] and
|
||||
@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
|
||||
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
|
||||
that ASCII characters are encoded as themselves). Thus, a single
|
||||
@scheme[read-char] may call @scheme[read-byte] multiple times, and a
|
||||
single @scheme[write-char] may generate multiple output bytes.
|
||||
@racket[read-char] may call @racket[read-byte] multiple times, and a
|
||||
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
|
||||
uses a different encoding, or if you want to generate a text stream in
|
||||
a different encoding, use @scheme[reencode-input-port] or
|
||||
@scheme[reencode-output-port]. The @scheme[reencode-input-port]
|
||||
a different encoding, use @racket[reencode-input-port] or
|
||||
@racket[reencode-output-port]. The @racket[reencode-input-port]
|
||||
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,
|
||||
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.
|
||||
|
||||
@; ----------------------------------------------------------------------
|
||||
@section{I/O Patterns}
|
||||
@section[#:tag "io-patterns"]{I/O Patterns}
|
||||
|
||||
@(begin
|
||||
(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
|
||||
@scheme[for] with @scheme[in-lines]:
|
||||
@racket[for] with @racket[in-lines]:
|
||||
|
||||
@interaction[
|
||||
(define (upcase-all in)
|
||||
|
@ -401,8 +427,8 @@ regular expression (see @secref["regexp"]) to the stream:
|
|||
(has-hello? (open-input-string "goodbye"))
|
||||
]
|
||||
|
||||
If you want to copy one port into another, use @scheme[copy-port] from
|
||||
@schememodname[scheme/port], which efficiently transfers large blocks
|
||||
If you want to copy one port into another, use @racket[copy-port] from
|
||||
@racketmodname[racket/port], which efficiently transfers large blocks
|
||||
when lots of data is available, but also transfers small blocks
|
||||
immediately if that's all that is available:
|
||||
|
||||
|
|
|
@ -8,14 +8,14 @@
|
|||
A @deftech{macro} is a syntactic form with an associated
|
||||
@deftech{transformer} that @deftech{expands} the original form
|
||||
into existing forms. To put it another way, a macro is an
|
||||
extension to the Scheme compiler. Most of the syntactic forms of
|
||||
@schememodname[scheme/base] and @schememodname[scheme] are
|
||||
extension to the Racket compiler. Most of the syntactic forms of
|
||||
@racketmodname[racket/base] and @racketmodname[racket] are
|
||||
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
|
||||
use. Scheme also supports arbitrary macro transformers that are
|
||||
implemented in Scheme---or in a macro-extended variant of Scheme.
|
||||
use. Racket also supports arbitrary macro transformers that are
|
||||
implemented in Racket---or in a macro-extended variant of Racket.
|
||||
|
||||
@local-table-of-contents[]
|
||||
|
||||
|
|
|
@ -2,16 +2,16 @@
|
|||
@(require scribble/manual
|
||||
scribble/eval
|
||||
"guide-utils.ss"
|
||||
(for-label scheme/match))
|
||||
(for-label racket/match))
|
||||
|
||||
@(begin
|
||||
(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}
|
||||
|
||||
The @scheme[match] form supports pattern matching on arbitrary Scheme
|
||||
values, as opposed to functions like @scheme[regexp-match] that
|
||||
The @racket[match] form supports pattern matching on arbitrary Racket
|
||||
values, as opposed to functions like @racket[regexp-match] that
|
||||
compare regular expressions to byte and character sequences (see
|
||||
@secref["regexp"]).
|
||||
|
||||
|
@ -20,15 +20,15 @@ compare regular expressions to byte and character sequences (see
|
|||
[pattern expr ...+] ...)
|
||||
]
|
||||
|
||||
The @scheme[match] form takes the result of @scheme[target-expr] and
|
||||
tries to match each @scheme[_pattern] in order. As soon as it finds a
|
||||
match, it evaluates the corresponding @scheme[_expr] sequence to
|
||||
obtain the result for the @scheme[match] form. If @scheme[_pattern]
|
||||
The @racket[match] form takes the result of @racket[target-expr] and
|
||||
tries to match each @racket[_pattern] in order. As soon as it finds a
|
||||
match, it evaluates the corresponding @racket[_expr] sequence to
|
||||
obtain the result for the @racket[match] form. If @racket[_pattern]
|
||||
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.
|
||||
|
||||
Most Scheme literal expressions can be used as patterns:
|
||||
Most Racket literal expressions can be used as patterns:
|
||||
|
||||
@interaction[
|
||||
#:eval match-eval
|
||||
|
@ -45,7 +45,7 @@ Most Scheme literal expressions can be used as patterns:
|
|||
[#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:
|
||||
|
||||
@interaction[
|
||||
|
@ -61,16 +61,16 @@ can be used to create patterns that match pairs, lists, and vectors:
|
|||
[(vector 1 2) 'vector])
|
||||
]
|
||||
|
||||
The @scheme[struct] construct matches an instance of a particular
|
||||
structure type:
|
||||
A constructor bound with @scheme[struct] also can be used as a pattern
|
||||
constructor:
|
||||
|
||||
@interaction[
|
||||
#:eval match-eval
|
||||
(define-struct shoe (size color))
|
||||
(define-struct hat (size style))
|
||||
(match (make-hat 23 'bowler)
|
||||
[(struct shoe (10 'white)) "bottom"]
|
||||
[(struct hat (23 'bowler)) "top"])
|
||||
(struct shoe (size color))
|
||||
(struct hat (size style))
|
||||
(match (hat 23 'bowler)
|
||||
[(shoe 10 'white) "bottom"]
|
||||
[(hat 23 'bowler) "top"])
|
||||
]
|
||||
|
||||
Unquoted, non-constructor identifiers in a pattern are @tech{pattern
|
||||
|
@ -106,8 +106,8 @@ result expression to a list of matches:
|
|||
[else 'other])
|
||||
(match '(1 2 3 4)
|
||||
[(list 1 x ... 4) x])
|
||||
(match (list (make-hat 23 'bowler) (make-hat 22 'pork-pie))
|
||||
[(list (struct hat (sz styl)) ...) (apply + sz)])
|
||||
(match (list (hat 23 'bowler) (hat 22 'pork-pie))
|
||||
[(list (hat sz styl) ...) (apply + sz)])
|
||||
]
|
||||
|
||||
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])
|
||||
]
|
||||
|
||||
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,
|
||||
@scheme[match-let] generalizes @scheme[let] to a @as-index{destructing
|
||||
@racket[match-let] generalizes @racket[let] to a @as-index{destructing
|
||||
bind}:
|
||||
|
||||
@interaction[
|
||||
|
@ -132,7 +132,7 @@ bind}:
|
|||
(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}
|
||||
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
#lang scribble/doc
|
||||
@(require scribble/manual
|
||||
scribble/eval
|
||||
scheme/class
|
||||
racket/class
|
||||
"guide-utils.ss")
|
||||
|
||||
@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
|
||||
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:
|
||||
|
||||
@interaction[
|
||||
(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:
|
||||
|
||||
@interaction[
|
||||
|
@ -36,7 +36,7 @@ constructed dynamically:
|
|||
]
|
||||
|
||||
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:
|
||||
|
||||
@interaction[
|
||||
|
@ -46,25 +46,25 @@ direct approach is to use first-class functions:
|
|||
(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
|
||||
@scheme[eval] might be appropriate. Simialrly, the @tech{REPL} reads
|
||||
expressions that are typed by a user and uses @scheme[eval] to
|
||||
@racket[eval] might be appropriate. Simialrly, the @tech{REPL} reads
|
||||
expressions that are typed by a user and uses @racket[eval] to
|
||||
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
|
||||
@scheme[dynamic-require], which is essentially a wrapper around
|
||||
@scheme[eval] to dynamically load the module code.
|
||||
@racket[dynamic-require], which is essentially a wrapper around
|
||||
@racket[eval] to dynamically load the module code.
|
||||
|
||||
@; ----------------------------------------
|
||||
|
||||
@subsection{Local Scopes}
|
||||
|
||||
The @scheme[eval] function cannot see local bindings in the context
|
||||
where it is called. For example, calling @scheme[eval] inside an
|
||||
unquoted @scheme[let] form to evaluate a formula does not make values
|
||||
visible for @scheme[x] and @scheme[y]:
|
||||
The @racket[eval] function cannot see local bindings in the context
|
||||
where it is called. For example, calling @racket[eval] inside an
|
||||
unquoted @racket[let] form to evaluate a formula does not make values
|
||||
visible for @racket[x] and @racket[y]:
|
||||
|
||||
@interaction[
|
||||
(define (broken-eval-formula formula)
|
||||
|
@ -74,29 +74,29 @@ visible for @scheme[x] and @scheme[y]:
|
|||
(broken-eval-formula '(+ x y))
|
||||
]
|
||||
|
||||
The @scheme[eval] function cannot see the @scheme[x] and @scheme[y]
|
||||
bindings precisely because it is a function, and Scheme is a lexically
|
||||
scoped language. Imagine if @scheme[eval] were implemented as
|
||||
The @racket[eval] function cannot see the @racket[x] and @racket[y]
|
||||
bindings precisely because it is a function, and Racket is a lexically
|
||||
scoped language. Imagine if @racket[eval] were implemented as
|
||||
|
||||
@schemeblock[
|
||||
@racketblock[
|
||||
(define (eval x)
|
||||
(eval-expanded (macro-expand x)))
|
||||
]
|
||||
|
||||
then at the point when @scheme[eval-expanded] is called, the most
|
||||
recent binding of @scheme[x] is to the expression to evaluate, not the
|
||||
@scheme[let] binding in @scheme[broken-eval-formula]. Lexical scope
|
||||
then at the point when @racket[eval-expanded] is called, the most
|
||||
recent binding of @racket[x] is to the expression to evaluate, not the
|
||||
@racket[let] binding in @racket[broken-eval-formula]. Lexical scope
|
||||
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.
|
||||
|
||||
You might imagine that even though @scheme[eval] cannot see the local
|
||||
bindings in @scheme[broken-eval-formula], there must actually be a
|
||||
data structure mapping @scheme[x] to @scheme[2] and @scheme[y] to
|
||||
@scheme[3], and you would like a way to get that data structure. In
|
||||
You might imagine that even though @racket[eval] cannot see the local
|
||||
bindings in @racket[broken-eval-formula], there must actually be a
|
||||
data structure mapping @racket[x] to @racket[2] and @racket[y] to
|
||||
@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
|
||||
every use of @scheme[x] with @scheme[2] at compile time, so that the
|
||||
local binding of @scheme[x] does not exist in any concrete sense at
|
||||
every use of @racket[x] with @racket[2] at compile time, so that the
|
||||
local binding of @racket[x] does not exist in any concrete sense at
|
||||
run-time. Even when variables cannot be eliminated by
|
||||
constant-folding, normally the names of the variables can be
|
||||
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}
|
||||
|
||||
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
|
||||
available bindings. A @deftech{namespace} is a first-class value that
|
||||
encapsulates the bindings available for dynamic evaluation.
|
||||
|
||||
@margin-note{Informally, the term @defterm{namespace} is sometimes
|
||||
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
|
||||
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
|
||||
@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
|
||||
following interaction successfully accesses @scheme[x] via
|
||||
@scheme[eval]:
|
||||
following interaction successfully accesses @racket[x] via
|
||||
@racket[eval]:
|
||||
|
||||
@interaction[
|
||||
(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 DrScheme's @onscreen{Module} language or supplying the file as a
|
||||
command-line argument to @exec{mzscheme}:
|
||||
in DrRacket or supplying the file as a command-line argument to
|
||||
@exec{racket}:
|
||||
|
||||
@schememod[
|
||||
scheme
|
||||
@racketmod[
|
||||
racket
|
||||
|
||||
(eval '(cons 1 2))
|
||||
]
|
||||
|
||||
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
|
||||
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.
|
||||
|
||||
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
|
||||
explicitly and install it for the call to eval:
|
||||
|
||||
@schememod[
|
||||
scheme
|
||||
@racketmod[
|
||||
racket
|
||||
|
||||
(define ns (make-base-namespace))
|
||||
(eval '(cons 1 2) ns) (code:comment @#,t{works})
|
||||
]
|
||||
|
||||
The @scheme[make-base-namespace] function creates a namespace that is
|
||||
initialized with the exports of @scheme[scheme/base]. The later
|
||||
The @racket[make-base-namespace] function creates a namespace that is
|
||||
initialized with the exports of @racket[racket/base]. The later
|
||||
section @secref["mk-namespace"] provides more information on creating
|
||||
and configuring namespaces.
|
||||
|
||||
|
@ -168,40 +171,40 @@ and configuring namespaces.
|
|||
|
||||
@subsection{Namespaces and Modules}
|
||||
|
||||
As with @scheme[let] bindings, lexical scope means that @scheme[eval]
|
||||
cannot automatically see the definitions of a @scheme[module] in which
|
||||
it is called. Unlike @scheme[let] bindings, however, Scheme provides a
|
||||
As with @racket[let] bindings, lexical scope means that @racket[eval]
|
||||
cannot automatically see the definitions of a @racket[module] in which
|
||||
it is called. Unlike @racket[let] bindings, however, Racket provides a
|
||||
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
|
||||
definitions as if they appears in the @scheme[module] body:
|
||||
definitions as if they appears in the @racket[module] body:
|
||||
|
||||
@interaction[
|
||||
(module m scheme/base
|
||||
(module m racket/base
|
||||
(define x 11))
|
||||
(require 'm)
|
||||
(define ns (module->namespace ''m))
|
||||
(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
|
||||
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
|
||||
@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
|
||||
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
|
||||
@scheme[namespace-anchor->namespace] to reel in the module's
|
||||
@racket[namespace-anchor->namespace] to reel in the module's
|
||||
namespace:
|
||||
|
||||
@schememod[
|
||||
scheme
|
||||
@racketmod[
|
||||
racket
|
||||
|
||||
(define-namespace-anchor a)
|
||||
(define ns (namespace-anchor->namespace a))
|
||||
|
@ -209,7 +212,7 @@ scheme
|
|||
(define x 1)
|
||||
(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[
|
||||
|
||||
@item{A mapping from identifiers to bindings. For example, a
|
||||
namespace might map the identifier @schemeidfont{lambda} to the
|
||||
@scheme[lambda] form. An ``empty'' namespace is one that maps
|
||||
namespace might map the identifier @racketidfont{lambda} to the
|
||||
@racket[lambda] form. An ``empty'' namespace is one that maps
|
||||
every identifier to an uninitialized top-level variable.}
|
||||
|
||||
@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
|
||||
context, as in @scheme[(eval '(lambda (x) (+ x 1)))]. The second
|
||||
mapping is used, for example, by @scheme[dynamic-require] to locate a
|
||||
module. The call @scheme[(eval '(require scheme/base))] normally uses
|
||||
context, as in @racket[(eval '(lambda (x) (+ x 1)))]. The second
|
||||
mapping is used, for example, by @racket[dynamic-require] to locate a
|
||||
module. The call @racket[(eval '(require racket/base))] normally uses
|
||||
both pieces: the identifier mapping determines the binding of
|
||||
@schemeidfont{require}; if it turns out to mean @scheme[require], then
|
||||
the module mapping is used to locate the @schememodname[scheme/base]
|
||||
@racketidfont{require}; if it turns out to mean @racket[require], then
|
||||
the module mapping is used to locate the @racketmodname[racket/base]
|
||||
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
|
||||
that contains a few primitive modules, and that is further populated
|
||||
by loading files and modules as specified on the command line or as
|
||||
supplied in the @tech{REPL}. Top-level @scheme[require] and
|
||||
@scheme[define] forms adjusts the identifier mapping, and module
|
||||
declarations (typically loaded on demand for a @scheme[require] form)
|
||||
supplied in the @tech{REPL}. Top-level @racket[require] and
|
||||
@racket[define] forms adjusts the identifier mapping, and module
|
||||
declarations (typically loaded on demand for a @racket[require] form)
|
||||
adjust the module mapping.
|
||||
|
||||
@; ----------------------------------------
|
||||
|
||||
@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
|
||||
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)])
|
||||
(namespace-require 'scheme))
|
||||
(namespace-require 'racket))
|
||||
]
|
||||
|
||||
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}
|
||||
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,
|
||||
instead of just attaching the primitive modules---whose names and
|
||||
organization are subject to change---a higher-level module is
|
||||
attached, such as @schememodname[scheme] or
|
||||
@schememodname[scheme/base].
|
||||
attached, such as @racketmodname[racket] or
|
||||
@racketmodname[racket/base].
|
||||
|
||||
The @scheme[make-base-empty-namespace] function provides a namespace
|
||||
that is empty, except that @schememodname[scheme/base] is
|
||||
The @racket[make-base-empty-namespace] function provides a namespace
|
||||
that is empty, except that @racketmodname[racket/base] is
|
||||
attached. The resulting namespace is still ``empty'' in the sense that
|
||||
the identifiers-to-bindings part of the namespace has no mappings;
|
||||
only the module mapping has been populated. Nevertheless, with an
|
||||
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
|
||||
@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
|
||||
namespace created with @scheme[make-base-empty-namespace] is enough to
|
||||
namespace created with @racket[make-base-empty-namespace] is enough to
|
||||
get started:
|
||||
|
||||
@schemeblock[
|
||||
@racketblock[
|
||||
(define (run-dsl file)
|
||||
(parameterize ([current-namespace (make-base-empty-namespace)])
|
||||
(namespace-require 'my-dsl)
|
||||
(load file)))
|
||||
]
|
||||
|
||||
Note that the @scheme[parameterize] of @scheme[current-namespace] does
|
||||
not affect the meaning of identifiers like @scheme[namespace-require]
|
||||
within the @scheme[parameterize] body. Those identifiers obtain their
|
||||
Note that the @racket[parameterize] of @racket[current-namespace] does
|
||||
not affect the meaning of identifiers like @racket[namespace-require]
|
||||
within the @racket[parameterize] body. Those identifiers obtain their
|
||||
meaning from the enclosing context (probably a module). Only
|
||||
expressions that are dynamic with respect to this code, such as the
|
||||
content of @scheme[load]ed files, are affected by the
|
||||
@scheme[parameterize].
|
||||
content of @racket[load]ed files, are affected by the
|
||||
@racket[parameterize].
|
||||
|
||||
Another subtle point in the above example is the use of
|
||||
@scheme[(namespace-require 'my-dsl)] instead of @scheme[(eval
|
||||
'(require my-dsl))]. The latter would not work, because @scheme[eval]
|
||||
needs to obtain a meaning for @scheme[require] in the namespace, and
|
||||
@racket[(namespace-require 'my-dsl)] instead of @racket[(eval
|
||||
'(require my-dsl))]. The latter would not work, because @racket[eval]
|
||||
needs to obtain a meaning for @racket[require] in the namespace, and
|
||||
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
|
||||
@scheme[(namespace-require 'scheme/base)] would introduce a binding
|
||||
for @schemeidfont{require} and make a subsequent @scheme[(eval
|
||||
@racket[(namespace-require 'racket/base)] would introduce a binding
|
||||
for @racketidfont{require} and make a subsequent @racket[(eval
|
||||
'(require my-dsl))] work. The above is better, not only because it is
|
||||
more compact, but also because it avoids introducing bindings that are
|
||||
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
|
||||
instantiated afresh if they are demanded by evaluation. For example,
|
||||
@schememodname[scheme/base] does not include
|
||||
@schememodname[scheme/class], and loading @schememodname[scheme/class]
|
||||
@racketmodname[racket/base] does not include
|
||||
@racketmodname[racket/class], and loading @racketmodname[racket/class]
|
||||
again will create a distinct class datatype:
|
||||
|
||||
@interaction[
|
||||
(require scheme/class)
|
||||
(require racket/class)
|
||||
(class? object%)
|
||||
(class?
|
||||
(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%)))
|
||||
]
|
||||
|
||||
For cases when dynamically loaded code needs to share more code and
|
||||
data with its context, use the @scheme[namespace-attach-module]
|
||||
function. The first argument to @scheme[namespace-attach-module] is a
|
||||
data with its context, use the @racket[namespace-attach-module]
|
||||
function. The first argument to @racket[namespace-attach-module] is a
|
||||
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
|
||||
shared:
|
||||
|
||||
@interaction[
|
||||
(require scheme/class)
|
||||
(require racket/class)
|
||||
(class?
|
||||
(let ([ns (make-base-empty-namespace)])
|
||||
(namespace-attach-module (current-namespace)
|
||||
'scheme/class
|
||||
'racket/class
|
||||
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%))))
|
||||
]
|
||||
|
||||
Within a module, however, the combination of
|
||||
@scheme[define-namespace-anchor] and
|
||||
@scheme[namespace-anchor->empty-namespace] offers a more reliable
|
||||
@racket[define-namespace-anchor] and
|
||||
@racket[namespace-anchor->empty-namespace] offers a more reliable
|
||||
method for obtaining a source namespace:
|
||||
|
||||
@schememod[
|
||||
scheme/base
|
||||
@racketmod[
|
||||
racket/base
|
||||
|
||||
(require scheme/class)
|
||||
(require racket/class)
|
||||
|
||||
(define-namespace-anchor a)
|
||||
|
||||
(define (load-plug-in file)
|
||||
(let ([ns (make-base-empty-namespace)])
|
||||
(namespace-attach-module (namespace-anchor->empty-namespace a)
|
||||
'scheme/class
|
||||
'racket/class
|
||||
ns)
|
||||
(parameterize ([current-namespace ns])
|
||||
(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
|
||||
(which might differ from the current namespace). In the above
|
||||
example, since the enclosing module requires
|
||||
@schememodname[scheme/class], the namespace produced by
|
||||
@scheme[namespace-anchor->empty-namespace] certainly contains an
|
||||
instance of @schememodname[scheme/class]. Moreover, that instance is
|
||||
@racketmodname[racket/class], the namespace produced by
|
||||
@racket[namespace-anchor->empty-namespace] certainly contains an
|
||||
instance of @racketmodname[racket/class]. Moreover, that instance is
|
||||
the same as the one imported into the module, so the class datatype is
|
||||
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
|
||||
the @tech{REPL} to evaluate program fragments in a particular order.
|
||||
While @tech{REPL} scripting turns out to be a bad way to structure
|
||||
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
|
||||
@cite["Flatt02"].}
|
||||
|
||||
The @scheme[load] function runs a @tech{REPL} script by
|
||||
@scheme[read]ing S-expressions from a file, one by one, and passing
|
||||
them to @scheme[eval]. If a file @filepath{place.scm} contains
|
||||
The @racket[load] function runs a @tech{REPL} script by
|
||||
@racket[read]ing S-expressions from a file, one by one, and passing
|
||||
them to @racket[eval]. If a file @filepath{place.rkts} contains
|
||||
|
||||
@schemeblock[
|
||||
@racketblock[
|
||||
(define city "Salt Lake City")
|
||||
(define state "Utah")
|
||||
(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}:
|
||||
|
||||
@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)))
|
||||
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
|
||||
@secref["namespaces"]:
|
||||
|
||||
@schememod[
|
||||
scheme
|
||||
@racketmod[
|
||||
racket
|
||||
|
||||
(define there "Utopia")
|
||||
|
||||
(load "here.scm")
|
||||
(load "here.rkts")
|
||||
]
|
||||
|
||||
The current namespace for evaluating the content of
|
||||
@filepath{here.scm} is likely to be empty; in any case, you cannot get
|
||||
@scheme[there] from @filepath{here.scm}. Also, any definitions in
|
||||
@filepath{here.scm} will not become visible for use within the module;
|
||||
after all, the @scheme[load] happens dynamically, while references to
|
||||
@filepath{here.rkts} is likely to be empty; in any case, you cannot get
|
||||
@racket[there] from @filepath{here.rkts}. Also, any definitions in
|
||||
@filepath{here.rkts} will not become visible for use within the module;
|
||||
after all, the @racket[load] happens dynamically, while references to
|
||||
identifiers within the module are resolved lexically, and therefore
|
||||
statically.
|
||||
|
||||
Unlike @scheme[eval], @scheme[load] does not accept a namespace
|
||||
argument. To supply a namespace to @scheme[load], set the
|
||||
@scheme[current-namespace] parameter. The following example evaluates
|
||||
the expressions in @filepath{here.scm} using the bindings of the
|
||||
@schememodname[scheme/base] module:
|
||||
Unlike @racket[eval], @racket[load] does not accept a namespace
|
||||
argument. To supply a namespace to @racket[load], set the
|
||||
@racket[current-namespace] @tech{parameter}. The following example evaluates
|
||||
the expressions in @filepath{here.rkts} using the bindings of the
|
||||
@racketmodname[racket/base] module:
|
||||
|
||||
@schememod[
|
||||
scheme
|
||||
@racketmod[
|
||||
racket
|
||||
|
||||
(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
|
||||
the following example, when @filepath{here.scm} is @scheme[load]ed, it
|
||||
can refer to @scheme[there] as well as the bindings of
|
||||
@schememodname[scheme]:
|
||||
the following example, when @filepath{here.rkts} is @racket[load]ed, it
|
||||
can refer to @racket[there] as well as the bindings of
|
||||
@racketmodname[racket]:
|
||||
|
||||
@schememod[
|
||||
scheme
|
||||
@racketmod[
|
||||
racket
|
||||
|
||||
(define there "Utopia")
|
||||
|
||||
(define-namespace-anchor 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
|
||||
module.
|
||||
|
||||
The @schememodname[scheme/load] module language is different from
|
||||
@schememodname[scheme] or @schememodname[scheme/base]. A module using
|
||||
@schememodname[scheme/load] treats all of its content as dynamic,
|
||||
passing each form in the module body to @scheme[eval] (using a
|
||||
namespace that is initialized with @schememodname[scheme]). As a
|
||||
result, uses of @scheme[eval] and @scheme[load] in the module body see
|
||||
The @racketmodname[racket/load] module language is different from
|
||||
@racketmodname[racket] or @racketmodname[racket/base]. A module using
|
||||
@racketmodname[racket/load] treats all of its content as dynamic,
|
||||
passing each form in the module body to @racket[eval] (using a
|
||||
namespace that is initialized with @racketmodname[racket]). As a
|
||||
result, uses of @racket[eval] and @racket[load] in the module body see
|
||||
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 (go!) (set! here there))
|
||||
]
|
||||
|
||||
then running
|
||||
|
||||
@schememod[
|
||||
scheme/load
|
||||
@racketmod[
|
||||
racket/load
|
||||
|
||||
(define there "Utopia")
|
||||
|
||||
(load "here.scm")
|
||||
(load "here.rkts")
|
||||
|
||||
(go!)
|
||||
(printf "~a\n" here)
|
||||
|
@ -500,12 +503,12 @@ scheme/load
|
|||
|
||||
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
|
||||
program
|
||||
|
||||
@schememod[
|
||||
scheme/load
|
||||
@racketmod[
|
||||
racket/load
|
||||
|
||||
(define good 5)
|
||||
(printf "running\n")
|
||||
|
@ -513,7 +516,7 @@ good
|
|||
bad
|
||||
]
|
||||
|
||||
DrScheme's @onscreen{Check Syntax} tool cannot tell that the second
|
||||
@scheme[good] is a reference to the first, and the unbound reference
|
||||
to @scheme[bad] is reported only at run time instead of rejected
|
||||
DrRacket's @onscreen{Check Syntax} tool cannot tell that the second
|
||||
@racket[good] is a reference to the first, and the unbound reference
|
||||
to @racket[bad] is reported only at run time instead of rejected
|
||||
syntactically.
|
||||
|
|
|
@ -4,22 +4,22 @@
|
|||
|
||||
@title{More Libraries}
|
||||
|
||||
@other-manual['(lib "scribblings/gui/gui.scrbl")] describes the PLT
|
||||
Scheme graphics toolbox, whose core is implemented by the @exec{mred}
|
||||
@other-manual['(lib "scribblings/gui/gui.scrbl")] describes the Racket
|
||||
graphics toolbox, whose core is implemented by the @exec{gracket}
|
||||
executable.
|
||||
|
||||
@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.
|
||||
|
||||
@other-manual['(lib "web-server/scribblings/web-server.scrbl")]
|
||||
describes the PLT Scheme web server, which supports servlets
|
||||
implemented in Scheme.
|
||||
describes the Racket web server, which supports servlets implemented
|
||||
in Racket.
|
||||
|
||||
@link["../index.html"]{PLT Scheme Documentation} lists documentation
|
||||
for many other installed libraries. Run @exec{plt-help} to find
|
||||
@link["../index.html"]{Racket Documentation} lists documentation for
|
||||
many other installed libraries. Run @exec{raco docs} to find
|
||||
documentation for libraries that are installed on your system and
|
||||
specific to your user account.
|
||||
|
||||
@link["http://planet.plt-scheme.org/"]{@|PLaneT|} offers even more
|
||||
downloadable packages contributed by PLT Scheme users.
|
||||
@link["http://planet.plt-racket.org/"]{@|PLaneT|} offers even more
|
||||
downloadable packages contributed by Racketeers.
|
||||
|
|
|
@ -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
|
||||
@scheme[define-syntax-rule]:
|
||||
@racket[define-syntax-rule]:
|
||||
|
||||
@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
|
||||
@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
|
||||
you add syntactic forms that some other language designer might not
|
||||
approve.}
|
||||
|
||||
@schemeblock[
|
||||
@racketblock[
|
||||
(define-syntax-rule (swap x y)
|
||||
(let ([tmp x])
|
||||
(set! x y)
|
||||
(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
|
||||
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
|
||||
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
|
||||
@scheme[_form_1] and @scheme[_form_2].
|
||||
macro matches the form @racket[(swap _form1 _form2)] for any
|
||||
@racket[_form_1] and @racket[_form_2].
|
||||
|
||||
@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
|
||||
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
|
||||
variable matched. For example, in
|
||||
|
||||
@schemeblock[(swap first last)]
|
||||
@racketblock[(swap first last)]
|
||||
|
||||
the pattern variable @scheme[x] matches @scheme[first] and @scheme[y]
|
||||
matches @scheme[last], so that the expansion is
|
||||
the pattern variable @racket[x] matches @racket[first] and @racket[y]
|
||||
matches @racket[last], so that the expansion is
|
||||
|
||||
@schemeblock[
|
||||
@racketblock[
|
||||
(let ([tmp first])
|
||||
(set! first last)
|
||||
(set! last tmp))
|
||||
|
@ -66,20 +66,20 @@ matches @scheme[last], so that the expansion is
|
|||
|
||||
@section{Lexical Scope}
|
||||
|
||||
Suppose that we use the @scheme[swap] macro to swap variables named
|
||||
@scheme[tmp] and @scheme[other]:
|
||||
Suppose that we use the @racket[swap] macro to swap variables named
|
||||
@racket[tmp] and @racket[other]:
|
||||
|
||||
@schemeblock[
|
||||
@racketblock[
|
||||
(let ([tmp 5]
|
||||
[other 6])
|
||||
(swap tmp other)
|
||||
(list tmp other))
|
||||
]
|
||||
|
||||
The result of the above expression should be @schemeresult[(6 5)]. The
|
||||
naive expansion of this use of @scheme[swap], however, is
|
||||
The result of the above expression should be @racketresult[(6 5)]. The
|
||||
naive expansion of this use of @racket[swap], however, is
|
||||
|
||||
@schemeblock[
|
||||
@racketblock[
|
||||
(let ([tmp 5]
|
||||
[other 6])
|
||||
(let ([tmp tmp])
|
||||
|
@ -88,14 +88,14 @@ naive expansion of this use of @scheme[swap], however, is
|
|||
(list tmp other))
|
||||
]
|
||||
|
||||
whose result is @schemeresult[(5 6)]. The problem is that the naive
|
||||
expansion confuses the @scheme[tmp] in the context where @scheme[swap]
|
||||
is used with the @scheme[tmp] that is in the macro template.
|
||||
whose result is @racketresult[(5 6)]. The problem is that the naive
|
||||
expansion confuses the @racket[tmp] in the context where @racket[swap]
|
||||
is used with the @racket[tmp] that is in the macro template.
|
||||
|
||||
Scheme doesn't produce the naive expansion for the above use of
|
||||
@scheme[swap]. Instead, it produces
|
||||
Racket doesn't produce the naive expansion for the above use of
|
||||
@racket[swap]. Instead, it produces
|
||||
|
||||
@schemeblock[
|
||||
@racketblock[
|
||||
(let ([tmp 5]
|
||||
[other 6])
|
||||
(let ([tmp_1 tmp])
|
||||
|
@ -104,10 +104,10 @@ Scheme doesn't produce the naive expansion for the above use of
|
|||
(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
|
||||
|
||||
@schemeblock[
|
||||
@racketblock[
|
||||
(let ([set! 5]
|
||||
[other 6])
|
||||
(swap set! other)
|
||||
|
@ -116,7 +116,7 @@ example
|
|||
|
||||
the expansion is
|
||||
|
||||
@schemeblock[
|
||||
@racketblock[
|
||||
(let ([set!_1 5]
|
||||
[other 6])
|
||||
(let ([tmp_1 tmp])
|
||||
|
@ -125,23 +125,23 @@ the expansion is
|
|||
(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.
|
||||
|
||||
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
|
||||
reference in macros and macro uses in the same way as for functions
|
||||
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
|
||||
single pattern, but Scheme's macro system supports transformers that
|
||||
The @racket[define-syntax-rule] form binds a macro that matches a
|
||||
single pattern, but Racket's macro system supports transformers that
|
||||
match multiple patterns starting with the same identifier. To write
|
||||
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:
|
||||
|
||||
@specform[#:literals (syntax-rules)
|
||||
|
@ -150,25 +150,25 @@ transformer form:
|
|||
[pattern template]
|
||||
...))]
|
||||
|
||||
@margin-note{The @scheme[define-syntax-rule] form is itself a macro
|
||||
that expands into @scheme[define-syntax] with a @scheme[syntax-rules]
|
||||
@margin-note{The @racket[define-syntax-rule] form is itself a macro
|
||||
that expands into @racket[define-syntax] with a @racket[syntax-rules]
|
||||
form that contains only one pattern and template.}
|
||||
|
||||
For example, suppose we would like a @scheme[rotate] macro that
|
||||
generalizes @scheme[swap] to work on either two or three identifiers,
|
||||
For example, suppose we would like a @racket[rotate] macro that
|
||||
generalizes @racket[swap] to work on either two or three identifiers,
|
||||
so that
|
||||
|
||||
@schemeblock[
|
||||
@racketblock[
|
||||
(let ([red 1] [green 2] [blue 3])
|
||||
(rotate red green) (code:comment @#,t{swaps})
|
||||
(rotate red green blue) (code:comment @#,t{rotates left})
|
||||
(list red green blue))
|
||||
]
|
||||
|
||||
produces @schemeresult[(1 3 2)]. We can implement @scheme[rotate]
|
||||
using @scheme[syntax-rules]:
|
||||
produces @racketresult[(1 3 2)]. We can implement @racket[rotate]
|
||||
using @racket[syntax-rules]:
|
||||
|
||||
@schemeblock[
|
||||
@racketblock[
|
||||
(define-syntax rotate
|
||||
(syntax-rules ()
|
||||
[(rotate a b) (swap a b)]
|
||||
|
@ -177,27 +177,27 @@ using @scheme[syntax-rules]:
|
|||
(swap b c))]))
|
||||
]
|
||||
|
||||
The expression @scheme[(rotate red green)] matches the first pattern
|
||||
in the @scheme[syntax-rules] form, so it expands to @scheme[(swap red
|
||||
green)]. The expression @scheme[(rotate a b c)] matches the second
|
||||
pattern, so it expands to @scheme[(begin (swap red green) (swap green
|
||||
The expression @racket[(rotate red green)] matches the first pattern
|
||||
in the @racket[syntax-rules] form, so it expands to @racket[(swap red
|
||||
green)]. The expression @racket[(rotate a b c)] matches the second
|
||||
pattern, so it expands to @racket[(begin (swap red green) (swap green
|
||||
blue))].
|
||||
|
||||
@; ----------------------------------------
|
||||
|
||||
@section{Matching Sequences}
|
||||
|
||||
A better @scheme[rotate] macro would allow any number of identifiers,
|
||||
instead of just two or three. To match a use of @scheme[rotate] with
|
||||
A better @racket[rotate] macro would allow any number of identifiers,
|
||||
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
|
||||
like a Kleene star. In a Scheme macro pattern, a star is written as
|
||||
@scheme[...].
|
||||
like a Kleene star. In a Racket macro pattern, a star is written as
|
||||
@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
|
||||
one identifier:
|
||||
|
||||
@schemeblock[
|
||||
@racketblock[
|
||||
(define-syntax rotate
|
||||
(syntax-rules ()
|
||||
[(rotate a) (void)]
|
||||
|
@ -206,19 +206,19 @@ one identifier:
|
|||
(rotate b c ...))]))
|
||||
]
|
||||
|
||||
When a pattern variable like @scheme[c] is followed by @scheme[...] in
|
||||
a pattern, then it must be followed by @scheme[...] in a template,
|
||||
When a pattern variable like @racket[c] is followed by @racket[...] in
|
||||
a pattern, then it must be followed by @racket[...] in a template,
|
||||
too. The pattern variable effectively matches a sequence of zero or
|
||||
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
|
||||
every variable in the sequence until it arrives at the last one. A
|
||||
more efficient @scheme[rotate] would move the first value directly to
|
||||
the last variable. We can use @scheme[...] patterns to implement the
|
||||
more efficient @racket[rotate] would move the first value directly to
|
||||
the last variable. We can use @racket[...] patterns to implement the
|
||||
more efficient variant using a helper macro:
|
||||
|
||||
@schemeblock[
|
||||
@racketblock[
|
||||
(define-syntax rotate
|
||||
(syntax-rules ()
|
||||
[(rotate a c ...)
|
||||
|
@ -232,18 +232,18 @@ more efficient variant using a helper macro:
|
|||
(set! to0 tmp))]))
|
||||
]
|
||||
|
||||
In the @scheme[shift-to] macro, @scheme[...] in the template follows
|
||||
@scheme[(set! to from)], which causes the @scheme[(set! to from)]
|
||||
In the @racket[shift-to] macro, @racket[...] in the template follows
|
||||
@racket[(set! to from)], which causes the @racket[(set! to from)]
|
||||
expression to be duplicated as many times as necessary to use each
|
||||
identifier matched in the @scheme[to] and @scheme[from]
|
||||
sequences. (The number of @scheme[to] and @scheme[from] matches must
|
||||
identifier matched in the @racket[to] and @racket[from]
|
||||
sequences. (The number of @racket[to] and @racket[from] matches must
|
||||
be the same, otherwise the macro expansion fails with an error.)
|
||||
|
||||
@; ----------------------------------------
|
||||
|
||||
@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
|
||||
error is reported:
|
||||
|
||||
|
@ -252,13 +252,13 @@ error is reported:
|
|||
@interaction[(+ swap 3)]
|
||||
|
||||
An @deftech{identifier macro} works in any expression. For example, we
|
||||
can define @scheme[clock] as an identifier macro that expands to
|
||||
@scheme[(get-clock)], so @scheme[(+ clock 3)] would expand to
|
||||
@scheme[(+ (get-clock) 3)]. An identifier macro also cooperates with
|
||||
@scheme[set!], and we can define @scheme[clock] so that @scheme[(set!
|
||||
clock 3)] expands to @scheme[(put-clock! 3)].
|
||||
can define @racket[clock] as an identifier macro that expands to
|
||||
@racket[(get-clock)], so @racket[(+ clock 3)] would expand to
|
||||
@racket[(+ (get-clock) 3)]. An identifier macro also cooperates with
|
||||
@racket[set!], and we can define @racket[clock] so that @racket[(set!
|
||||
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:
|
||||
|
||||
@specform[#:literals (syntax-id-rules)
|
||||
|
@ -267,12 +267,12 @@ it creates a transformer that acts as an identifier macro:
|
|||
[pattern template]
|
||||
...))]
|
||||
|
||||
Unlike a @scheme[syntax-rules] form, the @scheme[_pattern]s are not
|
||||
required to start with an open parenthesis. Also, @scheme[set!] is
|
||||
typically used as a literal to match a use of @scheme[set!] in the
|
||||
Unlike a @racket[syntax-rules] form, the @racket[_pattern]s are not
|
||||
required to start with an open parenthesis. Also, @racket[set!] is
|
||||
typically used as a literal to match a use of @racket[set!] in the
|
||||
pattern (as opposed to being a pattern variable.
|
||||
|
||||
@schemeblock[
|
||||
@racketblock[
|
||||
(define-syntax clock
|
||||
(syntax-id-rules (set!)
|
||||
[(set! clock e) (put-clock! e)]
|
||||
|
@ -280,29 +280,29 @@ pattern (as opposed to being a pattern variable.
|
|||
[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
|
||||
transformer is given the whole form, like with a non-identifier macro.
|
||||
Put another way, the @scheme[syntax-rules] form is essentially a
|
||||
special case of the @scheme[syntax-id-rules] form with errors in the
|
||||
@scheme[set!] and lone-identifier cases.
|
||||
Put another way, the @racket[syntax-rules] form is essentially a
|
||||
special case of the @racket[syntax-id-rules] form with errors in the
|
||||
@racket[set!] and lone-identifier cases.
|
||||
|
||||
@; ----------------------------------------
|
||||
|
||||
@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
|
||||
@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
|
||||
|
||||
@schemeblock[
|
||||
@racketblock[
|
||||
(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 id
|
||||
(syntax-id-rules (set!)
|
||||
|
@ -311,25 +311,25 @@ Naturally, we can implement @scheme[define-get/put-id] as a macro:
|
|||
[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
|
||||
@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.
|
||||
|
||||
@; ----------------------------------------
|
||||
|
||||
@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
|
||||
call-by-reference function body mutates its formal argument, the
|
||||
mutation applies to variables that are supplied as actual arguments in
|
||||
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
|
||||
|
||||
@schemeblock[
|
||||
@racketblock[
|
||||
(define-cbr (f a b)
|
||||
(swap a b))
|
||||
|
||||
|
@ -338,35 +338,35 @@ that it defines a call-by-reference function, then
|
|||
(list x y))
|
||||
]
|
||||
|
||||
produces @schemeresult[(2 1)].
|
||||
produces @racketresult[(2 1)].
|
||||
|
||||
We will implement call-by-reference functions by having function calls
|
||||
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
|
||||
|
||||
@schemeblock[
|
||||
@racketblock[
|
||||
(define (do-f get-a get-b put-a! put-b!)
|
||||
(define-get/put-id a get-a put-a!)
|
||||
(define-get/put-id b get-b put-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)
|
||||
(lambda () y)
|
||||
(lambda (v) (set! x v))
|
||||
(lambda (v) (set! y v)))
|
||||
]
|
||||
|
||||
Clearly, then @scheme[define-cbr] is a macro-generating macro, which
|
||||
binds @scheme[f] to a macro that expands to a call of @scheme[do-f].
|
||||
That is, @scheme[(define-cbr (f a b) (swap ab))] needs to generate the
|
||||
Clearly, then @racket[define-cbr] is a macro-generating macro, which
|
||||
binds @racket[f] to a macro that expands to a call of @racket[do-f].
|
||||
That is, @racket[(define-cbr (f a b) (swap ab))] needs to generate the
|
||||
definition
|
||||
|
||||
@schemeblock[
|
||||
@racketblock[
|
||||
(define-syntax f
|
||||
(syntax-rules ()
|
||||
[(id actual ...)
|
||||
|
@ -377,13 +377,13 @@ definition
|
|||
...)]))
|
||||
]
|
||||
|
||||
At the same time, @scheme[define-cbr] needs to define @scheme[do-f]
|
||||
using the body of @scheme[f], this second part is slightly more
|
||||
complex, so we defer most it to a @scheme[define-for-cbr] helper
|
||||
module, which lets us write @scheme[define-cbr] easily enough:
|
||||
At the same time, @racket[define-cbr] needs to define @racket[do-f]
|
||||
using the body of @racket[f], this second part is slightly more
|
||||
complex, so we defer most it to a @racket[define-for-cbr] helper
|
||||
module, which lets us write @racket[define-cbr] easily enough:
|
||||
|
||||
|
||||
@schemeblock[
|
||||
@racketblock[
|
||||
(define-syntax-rule (define-cbr (id arg ...) body)
|
||||
(begin
|
||||
(define-syntax id
|
||||
|
@ -399,34 +399,34 @@ module, which lets us write @scheme[define-cbr] easily enough:
|
|||
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
|
||||
|
||||
@schemeblock[
|
||||
@racketblock[
|
||||
(define-for-cbr do-f (a b) () (swap a b))
|
||||
]
|
||||
|
||||
to the function definition @scheme[do-f] above. Most of the work is
|
||||
generating a @scheme[define-get/put-id] declaration for each argument,
|
||||
@scheme[a] ad @scheme[b], and putting them before the body. Normally,
|
||||
that's an easy task for @scheme[...] in a pattern and template, but
|
||||
to the function definition @racket[do-f] above. Most of the work is
|
||||
generating a @racket[define-get/put-id] declaration for each argument,
|
||||
@racket[a] ad @racket[b], and putting them before the body. Normally,
|
||||
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
|
||||
@scheme[get-a] and @scheme[put-a!] as well as @scheme[get-b] and
|
||||
@scheme[put-b!], and the pattern language provides no way to
|
||||
@racket[get-a] and @racket[put-a!] as well as @racket[get-b] and
|
||||
@racket[put-b!], and the pattern language provides no way to
|
||||
synthesize identifiers based on existing identifiers.
|
||||
|
||||
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
|
||||
each argument in the function, and that's why @scheme[define-cbr]
|
||||
starts with an apparently useless @scheme[()] after the argument
|
||||
trick is to iterate expansions of @racket[define-for-cbr] once for
|
||||
each argument in the function, and that's why @racket[define-cbr]
|
||||
starts with an apparently useless @racket[()] after the argument
|
||||
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
|
||||
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
|
||||
(syntax-rules ()
|
||||
[(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:
|
||||
|
||||
@schemeblock[
|
||||
@racketblock[
|
||||
(define-for-cbr do-f (a b)
|
||||
() (swap a b))
|
||||
=> (define-for-cbr do-f (b)
|
||||
|
@ -455,11 +455,11 @@ Step-by-step, expansion proceeds as follows:
|
|||
(swap a b))
|
||||
]
|
||||
|
||||
The ``subscripts'' on @scheme[get_1], @scheme[get_2],
|
||||
@scheme[put_1], and @scheme[put_2] are inserted by the macro
|
||||
expander to preserve lexical scope, since the @scheme[get]
|
||||
generated by each iteration of @scheme[define-for-cbr] should not
|
||||
bind the @scheme[get] generated by a different iteration. In
|
||||
The ``subscripts'' on @racket[get_1], @racket[get_2],
|
||||
@racket[put_1], and @racket[put_2] are inserted by the macro
|
||||
expander to preserve lexical scope, since the @racket[get]
|
||||
generated by each iteration of @racket[define-for-cbr] should not
|
||||
bind the @racket[get] generated by a different iteration. In
|
||||
other words, we are essentially tricking the macro expander into
|
||||
generating fresh names for us, but the technique illustrates some
|
||||
of the surprising power of pattern-based macros with automatic
|
||||
|
@ -467,17 +467,17 @@ lexical scope.
|
|||
|
||||
The last expression eventually expands to just
|
||||
|
||||
@schemeblock[
|
||||
@racketblock[
|
||||
(define (do-f get_1 get_2 put_1 put_2)
|
||||
(let ([tmp (get_1)])
|
||||
(put_1 (get_2))
|
||||
(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
|
||||
Scheme with just three small pattern-based macros:
|
||||
@scheme[define-cbr], @scheme[define-for-cbr], and
|
||||
@scheme[define-get/put-id].
|
||||
Racket with just three small pattern-based macros:
|
||||
@racket[define-cbr], @racket[define-for-cbr], and
|
||||
@racket[define-get/put-id].
|
||||
|
||||
|
|
|
@ -1,31 +1,31 @@
|
|||
#lang scribble/doc
|
||||
@(require scribble/manual
|
||||
"guide-utils.ss"
|
||||
(for-label scheme/flonum scheme/unsafe/ops))
|
||||
(for-label racket/flonum racket/unsafe/ops))
|
||||
|
||||
@title[#:tag "performance"]{Performance}
|
||||
|
||||
Alan Perlis famously quipped ``Lisp programmers know the value of
|
||||
everything and the cost of nothing.'' A Scheme programmer knows, for
|
||||
example, that a @scheme[lambda] anywhere in a program produces a value
|
||||
everything and the cost of nothing.'' A Racket programmer knows, for
|
||||
example, that a @racket[lambda] anywhere in a program produces a value
|
||||
that is closed over it lexical environment---but how much does
|
||||
allocating that value cost? While most programmers have a reasonable
|
||||
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.
|
||||
|
||||
In this chapter, we narrow the gap by explaining details of the PLT
|
||||
Scheme compiler and run-time system and how they affect the run-time
|
||||
and memory performance of Scheme code.
|
||||
In this chapter, we narrow the gap by explaining details of the
|
||||
Racket compiler and run-time system and how they affect the run-time
|
||||
and memory performance of Racket code.
|
||||
|
||||
@; ----------------------------------------------------------------------
|
||||
|
||||
@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
|
||||
occurs automatically and on-the-fly. Tools like @exec{mzc} and
|
||||
@exec{setup-plt} marshal compiled bytecode to a file, so that you do
|
||||
occurs automatically and on-the-fly. Tools like @exec{raco make} and
|
||||
@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
|
||||
program. (Most of the time required to compile a file is actually in
|
||||
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
|
||||
constant propagation, constant folding, inlining, and dead-code
|
||||
elimination. For example, in an environment where @scheme[+] has its
|
||||
usual binding, the expression @scheme[(let ([x 1][y (lambda () 4)]) (+
|
||||
1 (y)))] is compiled the same as the constant @scheme[5].
|
||||
elimination. For example, in an environment where @racket[+] has its
|
||||
usual binding, the expression @racket[(let ([x 1][y (lambda () 4)]) (+
|
||||
1 (y)))] is compiled the same as the constant @racket[5].
|
||||
|
||||
On some platforms, bytecode is further compiled to native code via a
|
||||
@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
|
||||
numbers. Currently, @tech{JIT} compilation is supported for x86,
|
||||
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
|
||||
or the @DFlag{no-jit}/@Flag{j} command-line flag for @exec{mzscheme}.
|
||||
compiler can be disabled via the @racket[eval-jit-enabled] parameter
|
||||
or the @DFlag{no-jit}/@Flag{j} command-line flag for @exec{racket}.
|
||||
|
||||
The @tech{JIT} compiler works incrementally as functions are applied,
|
||||
but the @tech{JIT} compiler makes only limited use of run-time
|
||||
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,
|
||||
not counting the bodies of any lexically nested procedures. The
|
||||
overhead for @tech{JIT} compilation is normally so small that it is
|
||||
|
@ -61,33 +61,33 @@ difficult to detect.
|
|||
@section{Modules and Performance}
|
||||
|
||||
The module system aids optimization by helping to ensure that
|
||||
identifiers have the usual bindings. That is, the @scheme[+] provided
|
||||
by @schememodname[scheme/base] can be recognized by the compiler and
|
||||
identifiers have the usual bindings. That is, the @racket[+] provided
|
||||
by @racketmodname[racket/base] can be recognized by the compiler and
|
||||
inlined, which is especially important for @tech{JIT}-compiled code.
|
||||
In contrast, in a traditional interactive Scheme system, the top-level
|
||||
@scheme[+] binding might be redefined, so the compiler cannot assume a
|
||||
fixed @scheme[+] binding (unless special flags or declarations
|
||||
In contrast, in a traditional interactive Racket system, the top-level
|
||||
@racket[+] binding might be redefined, so the compiler cannot assume a
|
||||
fixed @racket[+] binding (unless special flags or declarations
|
||||
act as a poor-man's module system to indicate otherwise).
|
||||
|
||||
Even in the top-level environment, importing with @scheme[require]
|
||||
enables some inlining optimizations. Although a @scheme[+] definition
|
||||
at the top level might shadow an imported @scheme[+], the shadowing
|
||||
Even in the top-level environment, importing with @racket[require]
|
||||
enables some inlining optimizations. Although a @racket[+] definition
|
||||
at the top level might shadow an imported @racket[+], the shadowing
|
||||
definition applies only to expressions evaluated later.
|
||||
|
||||
Within a module, inlining and constant-propagation optimizations take
|
||||
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
|
||||
environment. Although this optimization within modules is important
|
||||
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
|
||||
definitions when interactive exploration is more important. See
|
||||
@secref["module-set"] for more information.
|
||||
|
||||
Currently, the compiler does not attempt to inline or propagate
|
||||
constants across module boundary, except for exports of the built-in
|
||||
modules (such as the one that originally provides @scheme[+]).
|
||||
constants across module boundaries, except for exports of the built-in
|
||||
modules (such as the one that originally provides @racket[+]).
|
||||
|
||||
The later section @secref["letrec-performance"] provides some
|
||||
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,
|
||||
especially for tail calls. For example, given the program
|
||||
|
||||
@schemeblock[
|
||||
@racketblock[
|
||||
(letrec ([odd (lambda (x)
|
||||
(if (zero? x)
|
||||
#f
|
||||
|
@ -112,23 +112,23 @@ especially for tail calls. For example, given the program
|
|||
(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
|
||||
optimizations.
|
||||
|
||||
Within a module form, @scheme[define]d variables are lexically scoped
|
||||
like @scheme[letrec] bindings, and definitions within a module
|
||||
Within a module form, @racket[define]d variables are lexically scoped
|
||||
like @racket[letrec] bindings, and definitions within a module
|
||||
therefore permit call optimizations, so
|
||||
|
||||
@schemeblock[
|
||||
@racketblock[
|
||||
(define (odd 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
|
||||
@scheme[cdr] are inlined at the machine-code level by the @tech{JIT}
|
||||
Primitive operations like @racket[pair?], @racket[car], and
|
||||
@racket[cdr] are inlined at the machine-code level by the @tech{JIT}
|
||||
compiler. See also the later section @secref["fixnums+flonums"] for
|
||||
information about inlined arithmetic operations.
|
||||
|
||||
|
@ -136,11 +136,11 @@ information about inlined arithmetic operations.
|
|||
|
||||
@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
|
||||
|
||||
@schememod[
|
||||
scheme/base
|
||||
@racketmod[
|
||||
racket/base
|
||||
|
||||
(define (subtract-one x)
|
||||
(set! x (sub1 x))
|
||||
|
@ -155,8 +155,8 @@ scheme/base
|
|||
|
||||
runs much more slowly than the equivalent
|
||||
|
||||
@schememod[
|
||||
scheme/base
|
||||
@racketmod[
|
||||
racket/base
|
||||
|
||||
(define (subtract-one x)
|
||||
(sub1 x))
|
||||
|
@ -168,16 +168,16 @@ scheme/base
|
|||
(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
|
||||
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
|
||||
effort is spent elsewhere.
|
||||
|
||||
More significantly, mutation can obscure bindings where inlining and
|
||||
constant-propagation might otherwise apply. For example, in
|
||||
|
||||
@schemeblock[
|
||||
@racketblock[
|
||||
(let ([minus1 #f])
|
||||
(set! minus1 sub1)
|
||||
(let loop ([n 4000000])
|
||||
|
@ -186,14 +186,14 @@ constant-propagation might otherwise apply. For example, in
|
|||
(loop (minus1 n)))))
|
||||
]
|
||||
|
||||
the @scheme[set!] obscures the fact that @scheme[minus1] is just
|
||||
another name for the built-in @scheme[sub1].
|
||||
the @racket[set!] obscures the fact that @racket[minus1] is just
|
||||
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,
|
||||
compiling uses of the bindings efficiently. When other kinds of
|
||||
bindings are mixed with procedures, the compiler may be less able to
|
||||
|
@ -201,7 +201,7 @@ determine the control flow.
|
|||
|
||||
For example,
|
||||
|
||||
@schemeblock[
|
||||
@racketblock[
|
||||
(letrec ([loop (lambda (x)
|
||||
(if (zero? x)
|
||||
'done
|
||||
|
@ -213,7 +213,7 @@ For example,
|
|||
|
||||
likely compiles to less efficient code than
|
||||
|
||||
@schemeblock[
|
||||
@racketblock[
|
||||
(letrec ([loop (lambda (x)
|
||||
(if (zero? x)
|
||||
'done
|
||||
|
@ -223,13 +223,13 @@ likely compiles to less efficient code than
|
|||
]
|
||||
|
||||
In the first case, the compiler likely does not know that
|
||||
@scheme[display] does not call @scheme[loop]. If it did, then
|
||||
@scheme[loop] might refer to @scheme[next] before the binding is
|
||||
@racket[display] does not call @racket[loop]. If it did, then
|
||||
@racket[loop] might refer to @racket[next] before the binding is
|
||||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
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
|
||||
operations are used directly. For functions that take any number of
|
||||
arguments, such as @scheme[+], inlining works for two or more
|
||||
arguments (except for @scheme[-], whose one-argument case is also
|
||||
arguments, such as @racket[+], inlining works for two or more
|
||||
arguments (except for @racket[-], whose one-argument case is also
|
||||
inlined) when the arguments are either all fixnums or all flonums.
|
||||
|
||||
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
|
||||
@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}
|
||||
compiler to generate code that avoids boxing and unboxing intermediate
|
||||
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
|
||||
storage. Finally, the compiler can detect some flonum-valued loop
|
||||
accumulators and avoid boxing of the accumulator. The bytecode
|
||||
decompiler (see @secref[#:doc '(lib "scribblings/mzc/mzc.scrbl")
|
||||
"decompile"]) annotates combinations where the JIT can avoid boxes with
|
||||
@schemeidfont{#%flonum}, @schemeidfont{#%as-flonum}, and
|
||||
@schemeidfont{#%from-flonum}.
|
||||
@racketidfont{#%flonum}, @racketidfont{#%as-flonum}, and
|
||||
@racketidfont{#%from-flonum}.
|
||||
|
||||
@margin-note{Unboxing of local bindings and accumualtors is not
|
||||
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
|
||||
operations allow unboxing, and sometimes they allow the compiler to
|
||||
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}
|
||||
|
||||
The @schememodname[scheme/unsafe/ops] library provides functions that
|
||||
are like other functions in @schememodname[scheme/base], but they
|
||||
The @racketmodname[racket/unsafe/ops] library provides functions that
|
||||
are like other functions in @racketmodname[racket/base], but they
|
||||
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
|
||||
and without checking that the given index is in bounds. For tight
|
||||
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.
|
||||
|
||||
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.
|
||||
|
||||
@; ----------------------------------------------------------------------
|
||||
|
||||
@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{generational garbage collector} that makes allocation
|
||||
relatively cheap for short-lived objects. The @tech{CGC} variant uses
|
||||
a @deftech{conservative garbage collector} which facilitates
|
||||
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
|
||||
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.
|
||||
For example,
|
||||
|
||||
@schemeblock[
|
||||
@racketblock[
|
||||
(let loop ([n 40000000][prev-thunk (lambda () #f)])
|
||||
(if (zero? n)
|
||||
(prev-thunk)
|
||||
|
@ -333,13 +333,13 @@ For example,
|
|||
(lambda () n))))
|
||||
]
|
||||
|
||||
allocates a closure on every iteration, since @scheme[(lambda () n)]
|
||||
effectively saves @scheme[n].
|
||||
allocates a closure on every iteration, since @racket[(lambda () n)]
|
||||
effectively saves @racket[n].
|
||||
|
||||
The compiler can eliminate many closures automatically. For example,
|
||||
in
|
||||
|
||||
@schemeblock[
|
||||
@racketblock[
|
||||
(let loop ([n 40000000][prev-val #f])
|
||||
(let ([prev-thunk (lambda () n)])
|
||||
(if (zero? n)
|
||||
|
@ -347,10 +347,10 @@ in
|
|||
(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
|
||||
|
||||
@schemeblock[
|
||||
@racketblock[
|
||||
(let n-loop ([n 400000])
|
||||
(if (zero? n)
|
||||
'done
|
||||
|
@ -360,9 +360,9 @@ application is visible, and so it is inlined. Similarly, in
|
|||
(m-loop (sub1 m))))))
|
||||
]
|
||||
|
||||
then the expansion of the @scheme[let] form to implement
|
||||
@scheme[m-loop] involves a closure over @scheme[n], but the compiler
|
||||
automatically converts the closure to pass itself @scheme[n] as an
|
||||
then the expansion of the @racket[let] form to implement
|
||||
@racket[m-loop] involves a closure over @racket[n], but the compiler
|
||||
automatically converts the closure to pass itself @racket[n] as an
|
||||
argument instead.
|
||||
|
||||
@; ----------------------------------------------------------------------
|
||||
|
|
|
@ -4,34 +4,34 @@
|
|||
"guide-utils.ss")
|
||||
|
||||
@(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
|
||||
(interaction-eval #:eval e body) ...
|
||||
(schemeblock body ...)))
|
||||
(racketblock body ...)))
|
||||
|
||||
@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
|
||||
compile time while expanding expressions to be evaluated at run time.
|
||||
The compile-time value associated with a transformer binding can be
|
||||
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}.
|
||||
|
||||
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
|
||||
@scheme[syntax-rules] form directly (instead of placing on the
|
||||
right-hand of a @scheme[define-syntax] form), the result is a
|
||||
@racket[syntax-rules] form directly (instead of placing on the
|
||||
right-hand of a @racket[define-syntax] form), the result is a
|
||||
procedure:
|
||||
|
||||
@interaction[
|
||||
(syntax-rules () [(nothing) something])
|
||||
]
|
||||
|
||||
Instead of using @scheme[syntax-rules], you can write your own macro
|
||||
transformer procedure directly using @scheme[lambda]. The argument to
|
||||
Instead of using @racket[syntax-rules], you can write your own macro
|
||||
transformer procedure directly using @racket[lambda]. The argument to
|
||||
the procedure is a values that represents the source form, and the
|
||||
result of the procedure must be a value that represents the
|
||||
replacement form.
|
||||
|
@ -45,37 +45,37 @@ replacement form.
|
|||
The input and output of a macro transformer (i.e., source and
|
||||
replacement forms) are represented as @deftech{syntax objects}. A
|
||||
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
|
||||
@scheme[(+ 1 2)] contains the symbol @scheme['+] and the numbers
|
||||
@scheme[1] and @scheme[2], all in a list. In addition to this quoted
|
||||
@racket[(+ 1 2)] contains the symbol @racket['+] and the numbers
|
||||
@racket[1] and @racket[2], all in a list. In addition to this quoted
|
||||
content, a syntax object associates source-location and
|
||||
lexical-binding information with each part of the form. The
|
||||
source-location information is used when reporting syntax errors (for
|
||||
example), and the lexical-biding information allows the macro system
|
||||
to maintain lexical scope. To accommodate this extra information, the
|
||||
represention of the expression @scheme[(+ 1 2)] is not merely
|
||||
@scheme['(+ 1 2)], but a packaging of @scheme['(+ 1 2)] into a syntax
|
||||
represention of the expression @racket[(+ 1 2)] is not merely
|
||||
@racket['(+ 1 2)], but a packaging of @racket['(+ 1 2)] into a syntax
|
||||
object.
|
||||
|
||||
To create a literal syntax object, use the @scheme[syntax] form:
|
||||
To create a literal syntax object, use the @racket[syntax] form:
|
||||
|
||||
@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],
|
||||
@litchar{#'} abbreviates @scheme[syntax]:
|
||||
In the same way that @litchar{'} abbreviates @racket[quote],
|
||||
@litchar{#'} abbreviates @racket[syntax]:
|
||||
|
||||
@interaction[
|
||||
#'(+ 1 2)
|
||||
]
|
||||
|
||||
A syntax object that contains just a symbol is an @deftech{identifier
|
||||
syntax object}. Scheme provides some additional operations specific to
|
||||
identifier syntax objects, including the @scheme[identifier?]
|
||||
syntax object}. Racket provides some additional operations specific to
|
||||
identifier syntax objects, including the @racket[identifier?]
|
||||
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:
|
||||
|
||||
@interaction[
|
||||
|
@ -83,7 +83,7 @@ to the same binding:
|
|||
(identifier? #'(+ 1 2))
|
||||
(free-identifier=? #'car #'cdr)
|
||||
(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 (let ([car 8])
|
||||
#'car))
|
||||
|
@ -93,13 +93,13 @@ The last example above, in particular, illustrates how syntax objects
|
|||
preserve lexical-context information.
|
||||
|
||||
To see the lists, symbols, numbers, @|etc| within a syntax object, use
|
||||
@scheme[syntax->datum]:
|
||||
@racket[syntax->datum]:
|
||||
|
||||
@interaction[
|
||||
(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
|
||||
information, leaving sub-forms that have their own information wrapped
|
||||
as syntax objects:
|
||||
|
@ -108,16 +108,16 @@ as syntax objects:
|
|||
(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
|
||||
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
|
||||
constructed.
|
||||
|
||||
The opposite of @scheme[syntax->datum] is, of course,
|
||||
@scheme[datum->syntax]. In addition to a datum like @scheme['(+ 1
|
||||
2)], @scheme[datum->syntax] needs an existing syntax object to donate
|
||||
The opposite of @racket[syntax->datum] is, of course,
|
||||
@racket[datum->syntax]. In addition to a datum like @racket['(+ 1
|
||||
2)], @racket[datum->syntax] needs an existing syntax object to donate
|
||||
its lexical context, and optionally another syntax object to donate
|
||||
its source location:
|
||||
|
||||
|
@ -127,44 +127,44 @@ its source location:
|
|||
#'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
|
||||
@scheme[#'srcloc] is used.
|
||||
@racket[#'srcloc] is used.
|
||||
|
||||
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
|
||||
with @scheme[syntax-e] eventually produces the syntax objects that
|
||||
were given to @scheme[datum->syntax].
|
||||
with @racket[syntax-e] eventually produces the syntax objects that
|
||||
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
|
||||
@scheme[syntax-e] to deconstruct the given syntax object, and it uses
|
||||
@scheme[datum->syntax] to construct the result. The
|
||||
@scheme[syntax-rules] form doesn't provide a way to escape from
|
||||
The procedure generated by @racket[syntax-rules] internally uses
|
||||
@racket[syntax-e] to deconstruct the given syntax object, and it uses
|
||||
@racket[datum->syntax] to construct the result. The
|
||||
@racket[syntax-rules] form doesn't provide a way to escape from
|
||||
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:
|
||||
|
||||
@specform[(syntax-case stx-expr (literal-id ...)
|
||||
[pattern expr]
|
||||
...)]
|
||||
|
||||
Unlike @scheme[syntax-rules], the @scheme[syntax-case] form does not
|
||||
produce a procedure. Instead, it starts with a @scheme[_stx-expr]
|
||||
Unlike @racket[syntax-rules], the @racket[syntax-case] form does not
|
||||
produce a procedure. Instead, it starts with a @racket[_stx-expr]
|
||||
expression that determines the syntax object to match against the
|
||||
@scheme[_pattern]s. Also, each @scheme[syntax-case] clause has a
|
||||
@scheme[_pattern] and @scheme[_expr], instead of a @scheme[_pattern]
|
||||
and @scheme[_template]. Within an @scheme[_expr], the @scheme[syntax]
|
||||
@racket[_pattern]s. Also, each @racket[syntax-case] clause has a
|
||||
@racket[_pattern] and @racket[_expr], instead of a @racket[_pattern]
|
||||
and @racket[_template]. Within an @racket[_expr], the @racket[syntax]
|
||||
form---usually abbreviated with @litchar{#'}---shifts into
|
||||
template-construction mode; if the @scheme[_expr] of a clause starts
|
||||
with @litchar{#'}, then we have something like a @scheme[syntax-rules]
|
||||
template-construction mode; if the @racket[_expr] of a clause starts
|
||||
with @litchar{#'}, then we have something like a @racket[syntax-rules]
|
||||
form:
|
||||
|
||||
@interaction[
|
||||
|
@ -173,10 +173,10 @@ form:
|
|||
[(op n1 n2) #'(- n1 n2)]))
|
||||
]
|
||||
|
||||
We could write the @scheme[swap] macro using @scheme[syntax-case]
|
||||
instead of @scheme[define-syntax-rule] or @scheme[syntax-rules]:
|
||||
We could write the @racket[swap] macro using @racket[syntax-case]
|
||||
instead of @racket[define-syntax-rule] or @racket[syntax-rules]:
|
||||
|
||||
@schemeblock[
|
||||
@racketblock[
|
||||
(define-syntax swap
|
||||
(lambda (stx)
|
||||
(syntax-case stx ()
|
||||
|
@ -185,15 +185,15 @@ instead of @scheme[define-syntax-rule] or @scheme[syntax-rules]:
|
|||
(set! y tmp))])))
|
||||
]
|
||||
|
||||
One advantage of using @scheme[syntax-case] is that we can provide
|
||||
better error reporting for @scheme[swap]. For example, with the
|
||||
@scheme[define-syntax-rule] definition of @scheme[swap], then
|
||||
@scheme[(swap x 2)] produces a syntax error in terms of @scheme[set!],
|
||||
because @scheme[2] is not an identifier. We can refine our
|
||||
@scheme[syntax-case] implementation of @scheme[swap] to explicitly
|
||||
One advantage of using @racket[syntax-case] is that we can provide
|
||||
better error reporting for @racket[swap]. For example, with the
|
||||
@racket[define-syntax-rule] definition of @racket[swap], then
|
||||
@racket[(swap x 2)] produces a syntax error in terms of @racket[set!],
|
||||
because @racket[2] is not an identifier. We can refine our
|
||||
@racket[syntax-case] implementation of @racket[swap] to explicitly
|
||||
check the sub-forms:
|
||||
|
||||
@schemeblock[
|
||||
@racketblock[
|
||||
(define-syntax swap
|
||||
(lambda (stx)
|
||||
(syntax-case stx ()
|
||||
|
@ -211,29 +211,29 @@ check the sub-forms:
|
|||
#'x)))])))
|
||||
]
|
||||
|
||||
With this definition, @scheme[(swap x 2)] provides a syntax error
|
||||
originating from @scheme[swap] instead of @scheme[set!].
|
||||
With this definition, @racket[(swap x 2)] provides a syntax error
|
||||
originating from @racket[swap] instead of @racket[set!].
|
||||
|
||||
In the above definition of @scheme[swap], @scheme[#'x] and
|
||||
@scheme[#'y] are templates, even though they are not used as the
|
||||
In the above definition of @racket[swap], @racket[#'x] and
|
||||
@racket[#'y] are templates, even though they are not used as the
|
||||
result of the macro transformer. This example illustrates how
|
||||
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
|
||||
@scheme[#'x] or @scheme[#'y] is used in the call to
|
||||
@scheme[raise-syntax-error], so that the syntax-error message can
|
||||
@racket[#'x] or @racket[#'y] is used in the call to
|
||||
@racket[raise-syntax-error], so that the syntax-error message can
|
||||
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
|
||||
writing @scheme[define-for-cbr] (see
|
||||
writing @racket[define-for-cbr] (see
|
||||
@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)
|
||||
(syntax-case stx ()
|
||||
[(_ do-f (id ...) body)
|
||||
|
@ -243,17 +243,17 @@ set of names based on a sequence @scheme[id ...]:
|
|||
body) ....]))
|
||||
]
|
||||
|
||||
@margin-note{This example uses @scheme[(define-syntax (_id _arg) _body ...+)],
|
||||
which is equivalent to @scheme[(define-syntax _id (lambda (_arg) _body ...+))].}
|
||||
@margin-note{This example uses @racket[(define-syntax (_id _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
|
||||
...] and @scheme[put ...] to lists of generated identifiers. We
|
||||
cannot use @scheme[let] to bind @scheme[get] and @scheme[put],
|
||||
In place of the @racket[....]s above, we need to bind @racket[get
|
||||
...] and @racket[put ...] to lists of generated identifiers. We
|
||||
cannot use @racket[let] to bind @racket[get] and @racket[put],
|
||||
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:
|
||||
|
||||
@schemeblock[
|
||||
@racketblock[
|
||||
(define-syntax (define-for-cbr stx)
|
||||
(syntax-case stx ()
|
||||
[(_ do-f (id ...) body)
|
||||
|
@ -264,14 +264,14 @@ bind pattern variables:
|
|||
body))]))
|
||||
]
|
||||
|
||||
Now we need an expression in place of @scheme[....] that
|
||||
generates as many identifiers as there are @scheme[id] matches in
|
||||
the original pattern. Since this is a common task, Scheme
|
||||
provides a helper function, @scheme[generate-temporaries], that
|
||||
Now we need an expression in place of @racket[....] that
|
||||
generates as many identifiers as there are @racket[id] matches in
|
||||
the original pattern. Since this is a common task, Racket
|
||||
provides a helper function, @racket[generate-temporaries], that
|
||||
takes a sequece of identifiers and returns a sequence of
|
||||
generated identifiers:
|
||||
|
||||
@schemeblock[
|
||||
@racketblock[
|
||||
(define-syntax (define-for-cbr stx)
|
||||
(syntax-case stx ()
|
||||
[(_ 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
|
||||
purely pattern-based macros.
|
||||
|
||||
In general, the right-hand side of a @scheme[with-syntax]
|
||||
binding is a pattern, just like in @scheme[syntax-case]. In fact,
|
||||
a @scheme[with-syntax] form is just a @scheme[syntax-case] form
|
||||
In general, the right-hand side of a @racket[with-syntax]
|
||||
binding is a pattern, just like in @racket[syntax-case]. In fact,
|
||||
a @racket[with-syntax] form is just a @racket[syntax-case] form
|
||||
turned partially inside-out.
|
||||
|
||||
@; ----------------------------------------
|
||||
|
@ -297,13 +297,13 @@ turned partially inside-out.
|
|||
|
||||
As sets of macros get more complicated, you might want to write
|
||||
your own helper functions, like
|
||||
@scheme[generate-temporaries]. For example, to provide good
|
||||
syntax-error messsage, @scheme[swap], @scheme[rotate], and
|
||||
@scheme[define-cbr] all should check that certain sub-forms in
|
||||
@racket[generate-temporaries]. For example, to provide good
|
||||
syntax-error messsage, @racket[swap], @racket[rotate], and
|
||||
@racket[define-cbr] all should check that certain sub-forms in
|
||||
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
|
||||
(define-syntax (swap stx)
|
||||
(syntax-case stx ()
|
||||
|
@ -321,11 +321,11 @@ the source form are identifiers. We could use a
|
|||
#'(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
|
||||
of syntax objects:
|
||||
|
||||
@schemeblock[
|
||||
@racketblock[
|
||||
(define (check-ids stx forms)
|
||||
(for-each
|
||||
(lambda (form)
|
||||
|
@ -337,7 +337,7 @@ of syntax objects:
|
|||
(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:
|
||||
|
||||
@interaction[
|
||||
|
@ -345,18 +345,18 @@ however, it doesn't work:
|
|||
(let ([a 1] [b 2]) (swap a b))
|
||||
]
|
||||
|
||||
The problem is that @scheme[check-ids] is defined as a run-time
|
||||
expression, but @scheme[swap] is trying to use it at compile time. In
|
||||
The problem is that @racket[check-ids] is defined as a run-time
|
||||
expression, but @racket[swap] is trying to use it at compile time. In
|
||||
interactive mode, compile time and run time are interleaved, but they
|
||||
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
|
||||
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.
|
||||
|
||||
To define a @scheme[check-ids] function that can be referenced at
|
||||
compile time, use @scheme[define-for-syntax]:
|
||||
To define a @racket[check-ids] function that can be referenced at
|
||||
compile time, use @racket[define-for-syntax]:
|
||||
|
||||
@schemeblock/eval[
|
||||
@racketblock/eval[
|
||||
#:eval check-eval
|
||||
(define-for-syntax (check-ids stx forms)
|
||||
(for-each
|
||||
|
@ -369,7 +369,7 @@ compile time, use @scheme[define-for-syntax]:
|
|||
(syntax->list forms)))
|
||||
]
|
||||
|
||||
With this for-syntax definition, then @scheme[swap] works:
|
||||
With this for-syntax definition, then @racket[swap] works:
|
||||
|
||||
@interaction[
|
||||
#: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
|
||||
functions in one module to be used by macros that reside on other
|
||||
modules. In that case, you can write the helper function using
|
||||
@scheme[define]:
|
||||
@racket[define]:
|
||||
|
||||
@schememod[#:file
|
||||
@racketmod[#:file
|
||||
"utils.ss"
|
||||
scheme
|
||||
racket
|
||||
|
||||
(provide check-ids)
|
||||
|
||||
|
@ -400,11 +400,11 @@ scheme
|
|||
]
|
||||
|
||||
Then, in the module that implements macros, import the helper function
|
||||
using @scheme[(require (for-syntax "utils.ss"))] instead of
|
||||
@scheme[(require "utils.ss")]:
|
||||
using @racket[(require (for-syntax "utils.ss"))] instead of
|
||||
@racket[(require "utils.ss")]:
|
||||
|
||||
@schememod[
|
||||
scheme
|
||||
@racketmod[
|
||||
racket
|
||||
|
||||
(require (for-syntax "utils.ss"))
|
||||
|
||||
|
@ -420,38 +420,38 @@ scheme
|
|||
Since modules are separately compiled and cannot have circular
|
||||
dependencies, the @filepath["utils.ss"] module's run-time body can be
|
||||
compiled before the compiling the module that implements
|
||||
@scheme[swap]. Thus, the run-time definitions in
|
||||
@filepath["utils.ss"] can be used to implement @scheme[swap], as long
|
||||
as they are explicitly shifted into compile time by @scheme[(require
|
||||
@racket[swap]. Thus, the run-time definitions in
|
||||
@filepath["utils.ss"] can be used to implement @racket[swap], as long
|
||||
as they are explicitly shifted into compile time by @racket[(require
|
||||
(for-syntax ....))].
|
||||
|
||||
The @schememodname[scheme] module provides @scheme[syntax-case],
|
||||
@scheme[generate-temporaries], @scheme[lambda], @scheme[if], and more
|
||||
The @racketmodname[racket] module provides @racket[syntax-case],
|
||||
@racket[generate-temporaries], @racket[lambda], @racket[if], and more
|
||||
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
|
||||
directly and in the right-hand side of a @scheme[define-syntax]
|
||||
can use @racket[syntax-case] in the @exec{racket} @tech{REPL} both
|
||||
directly and in the right-hand side of a @racket[define-syntax]
|
||||
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
|
||||
that defines @scheme[swap] so that it uses the
|
||||
@schememodname[scheme/base] language instead of
|
||||
@schememodname[scheme], then it no longer works. Adding
|
||||
@scheme[(require (for-syntax scheme/base))] imports
|
||||
@scheme[syntax-case] and more into the compile-time phase, so that the
|
||||
that defines @racket[swap] so that it uses the
|
||||
@racketmodname[racket/base] language instead of
|
||||
@racketmodname[racket], then it no longer works. Adding
|
||||
@racket[(require (for-syntax racket/base))] imports
|
||||
@racket[syntax-case] and more into the compile-time phase, so that the
|
||||
module works again.
|
||||
|
||||
Suppose that @scheme[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 the inner @scheme[define-syntax] is in the
|
||||
Suppose that @racket[define-syntax] is used to define a local macro in
|
||||
the right-hand side of a @racket[define-syntax] form. In that case,
|
||||
the right-hand side of the inner @racket[define-syntax] is in the
|
||||
@deftech{meta-compile phase level}, also known as @deftech{phase level
|
||||
2}. To import @scheme[syntax-case] into that phase level, you would
|
||||
have to use @scheme[(require (for-syntax (for-syntax scheme/base)))]
|
||||
or, equivalently, @scheme[(require (for-meta 2 scheme/base))].
|
||||
2}. To import @racket[syntax-case] into that phase level, you would
|
||||
have to use @racket[(require (for-syntax (for-syntax racket/base)))]
|
||||
or, equivalently, @racket[(require (for-meta 2 racket/base))].
|
||||
|
||||
Negative phase levels also exist. If a macro uses a helper function
|
||||
that is imported @scheme[for-syntax], and if the helper function
|
||||
returns syntax-object constants generated by @scheme[syntax], then
|
||||
that is imported @racket[for-syntax], and if the helper function
|
||||
returns syntax-object constants generated by @racket[syntax], then
|
||||
identifiers in the syntax will need bindings at @deftech{phase level
|
||||
-1}, also known as the @deftech{template phase level}, to have any
|
||||
binding at the run-time phase level relative to the module that
|
||||
|
|
|
@ -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
|
||||
pattern against (a portion of) another string or byte string, which we
|
||||
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.
|
||||
|
||||
@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}
|
||||
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, and @scheme[#rx#"abc"] is a @tech{byte
|
||||
@tech{regexp} value. For example, @racket[#rx"abc"] is a string-based
|
||||
@tech{regexp} value, and @racket[#rx#"abc"] is a @tech{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.
|
||||
|
||||
Most of the characters in a @tech{regexp} pattern are meant to match
|
||||
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
|
||||
characters act as @deftech{metacharacters}, and some character
|
||||
sequences act as @deftech{metasequences}. That is, they specify
|
||||
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
|
||||
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.
|
||||
|
||||
@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
|
||||
at all. Scheme strings use @litchar{\} as the escape character, so we
|
||||
end up with two @litchar{\}s: one Scheme-string @litchar{\} to escape
|
||||
at all. Racket strings use @litchar{\} as the escape character, so we
|
||||
end up with two @litchar{\}s: one Racket-string @litchar{\} to escape
|
||||
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{"}.}
|
||||
|
||||
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
|
||||
itself but rather just @litchar{.}. So, to match @litchar{a},
|
||||
@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.
|
||||
|
||||
The @scheme[regexp] function takes a string or byte string and
|
||||
produces a @tech{regexp} value. Use @scheme[regexp] when you construct
|
||||
The @racket[regexp] function takes a string or byte string and
|
||||
produces a @tech{regexp} value. Use @racket[regexp] when you construct
|
||||
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.
|
||||
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
|
||||
@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
|
||||
string. In particular, characters in the input string that could serve
|
||||
as regexp metacharacters are escaped with a backslash, so that they
|
||||
|
@ -79,7 +79,7 @@ safely match only themselves.
|
|||
(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.
|
||||
|
||||
|
||||
|
@ -87,9 +87,9 @@ The @scheme[regexp-quote] function is useful when building a composite
|
|||
|
||||
@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
|
||||
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
|
||||
@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")
|
||||
]
|
||||
|
||||
In the second example, the integers @scheme[4] and @scheme[10]
|
||||
identify the substring that was matched. The @scheme[4] is the
|
||||
starting (inclusive) index, and @scheme[10] the ending (exclusive)
|
||||
In the second example, the integers @racket[4] and @racket[10]
|
||||
identify the substring that was matched. The @racket[4] is the
|
||||
starting (inclusive) index, and @racket[10] the ending (exclusive)
|
||||
index of the matching substring:
|
||||
|
||||
@interaction[
|
||||
(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
|
||||
substring matched by the regexp. When we discuss @tech{subpatterns}
|
||||
later, we will see how a single match operation can yield a list of
|
||||
@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
|
||||
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
|
||||
@tech{text string}.
|
||||
|
||||
The @scheme[regexp-match] function is like
|
||||
@scheme[regexp-match-positions], but instead of returning index pairs,
|
||||
The @racket[regexp-match] function is like
|
||||
@racket[regexp-match-positions], but instead of returning index pairs,
|
||||
it returns the matching substrings:
|
||||
|
||||
@interaction[
|
||||
|
@ -136,7 +136,7 @@ it returns the matching substrings:
|
|||
(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:
|
||||
|
||||
@interaction[
|
||||
|
@ -153,7 +153,7 @@ is a matching byte substring:
|
|||
avoids UTF-8 encodings.}
|
||||
|
||||
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:
|
||||
|
||||
@interaction[
|
||||
|
@ -163,8 +163,8 @@ port directly:
|
|||
(regexp-match #rx#"needle" i)
|
||||
]
|
||||
|
||||
The @scheme[regexp-match?] function is like
|
||||
@scheme[regexp-match-positions], but simply returns a boolean
|
||||
The @racket[regexp-match?] function is like
|
||||
@racket[regexp-match-positions], but simply returns a boolean
|
||||
indicating whether the match succeeded:
|
||||
|
||||
@interaction[
|
||||
|
@ -172,7 +172,7 @@ indicating whether the match succeeded:
|
|||
(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
|
||||
substrings of the text string; the pattern identifies the delimiter
|
||||
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
|
||||
use the regexp @scheme[#rx"\u20+"], not @scheme[#rx"\u20*"].
|
||||
use the regexp @racket[#rx"\u20+"], not @racket[#rx"\u20*"].
|
||||
|
||||
@interaction[
|
||||
(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 second the text string, and the third is either the string to be
|
||||
inserted or a procedure to convert matches to the insert string.
|
||||
|
||||
@interaction[
|
||||
(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
|
||||
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:
|
||||
|
||||
@interaction[
|
||||
(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
|
||||
character class} @litchar{[}...@litchar{]}, which matches any one
|
||||
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
|
||||
nothing else.
|
||||
|
||||
Inside the brackets, a @litchar{-} between two characters specifies
|
||||
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{tap}.
|
||||
|
||||
An initial @litchar{^} after the left bracket inverts the set
|
||||
specified by the rest of the contents; i.e., it specifies the set of
|
||||
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}.
|
||||
|
||||
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; see below). Thus, a @litchar{[} inside a bracketed character
|
||||
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}.
|
||||
|
||||
Furthermore, since empty bracketed character classes are disallowed, a
|
||||
@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}.
|
||||
|
||||
@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
|
||||
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
|
||||
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.
|
||||
|
||||
Remember to include a double backslash when putting these
|
||||
metasequences in a Scheme string:
|
||||
metasequences in a Racket string:
|
||||
|
||||
@interaction[
|
||||
(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
|
||||
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.
|
||||
|
||||
@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.
|
||||
|
||||
@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
|
||||
if the overall pattern matches. In such cases, the failing submatch
|
||||
is represented by @scheme[#f]
|
||||
is represented by @racket[#f]
|
||||
|
||||
@interaction[
|
||||
(define date-re
|
||||
|
@ -531,7 +531,7 @@ is represented by @scheme[#f]
|
|||
@subsection{Backreferences}
|
||||
|
||||
@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}
|
||||
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
|
||||
|
@ -612,11 +612,11 @@ In the following example, a non-capturing cluster eliminates the
|
|||
cluster identifies the basename.
|
||||
|
||||
@margin-note{But don't parse paths with regexps. Use functions like
|
||||
@scheme[split-path], instead.}
|
||||
@racket[split-path], instead.}
|
||||
|
||||
@interaction[
|
||||
(regexp-match #rx"^(?:[a-z]*/)*([a-z]+)$"
|
||||
"/usr/local/bin/mzscheme")
|
||||
"/usr/local/bin/racket")
|
||||
]
|
||||
|
||||
@subsection[#:tag "regexp-cloister"]{Cloisters}
|
||||
|
@ -734,7 +734,7 @@ Consider
|
|||
|
||||
The regexp consists of two subregexps: @litchar{a*} followed by
|
||||
@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
|
||||
three, leaving the last one for the second subregexp. This ensures
|
||||
that the full regexp matches successfully.
|
||||
|
@ -800,7 +800,7 @@ its subpattern @emph{could} match.
|
|||
"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
|
||||
@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 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
|
||||
@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 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}.
|
||||
|
||||
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 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}.
|
||||
|
||||
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
|
||||
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:
|
||||
|
||||
@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
|
||||
@secref["regexp-alternation"]. However, since we intend to anchor
|
||||
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 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.
|
||||
|
||||
@interaction[
|
||||
|
@ -894,10 +894,10 @@ three dots separating them.
|
|||
(define ip-re1
|
||||
(string-append
|
||||
"^" (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{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})
|
||||
"{3}" (code:comment @#,t{repeated exactly 3 times})
|
||||
"$" (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
|
||||
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 there @emph{is} a digit other than zero.
|
||||
|
||||
|
@ -946,7 +946,7 @@ composed of @emph{only} zeros and dots.
|
|||
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[
|
||||
#:eval ex-eval
|
||||
|
|
|
@ -1,142 +1,141 @@
|
|||
#lang scribble/doc
|
||||
@(require scribble/manual
|
||||
"guide-utils.ss"
|
||||
(for-syntax scheme/pretty))
|
||||
(for-syntax racket/pretty))
|
||||
|
||||
@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")
|
||||
"top"]{DrScheme} programming environment. To run a program without the
|
||||
development environment, use @exec{mzscheme} (for console-based
|
||||
programs) or @exec{mred} (for GUI program). This chapter mainly
|
||||
explains how to run @exec{mzscheme} and @exec{mred}.
|
||||
"top"]{DrRacket} programming environment. To run a program without the
|
||||
development environment, use @exec{racket} (for console-based
|
||||
programs) or @exec{gracket} (for GUI programs). This chapter mainly
|
||||
explains how to run @exec{racket} and @exec{gracket}.
|
||||
|
||||
@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},
|
||||
@seclink["start-module-mode"]{module mode}, or
|
||||
@seclink["start-load-mode"]{load 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}
|
||||
with a @litchar{> } prompt:
|
||||
|
||||
@verbatim[#:indent 2]{
|
||||
Welcome to MzScheme
|
||||
Welcome to Racket
|
||||
>
|
||||
}
|
||||
|
||||
@margin-note{For information on GNU Readline support, see
|
||||
@schememodname[readline].}
|
||||
@racketmodname[readline].}
|
||||
|
||||
To initialize the @tech{REPL}'s environment, @exec{mzscheme} first
|
||||
requires the @schememodname[scheme/init] module, which provides all of
|
||||
@scheme[scheme], and also installs @scheme[pretty-print] for display
|
||||
results. Finally, @exec{mzscheme} loads the file reported by
|
||||
@scheme[(find-system-path 'init-file)], if it exists, before starting
|
||||
To initialize the @tech{REPL}'s environment, @exec{racket} first
|
||||
requires the @racketmodname[racket/init] module, which provides all of
|
||||
@racket[racket], and also installs @racket[pretty-print] for display
|
||||
results. Finally, @exec{racket} loads the file reported by
|
||||
@racket[(find-system-path 'init-file)], if it exists, before starting
|
||||
the @tech{REPL}.
|
||||
|
||||
If any command-line arguments are provided (other than configuration
|
||||
options), add @Flag{i} or @DFlag{repl} to re-enable the
|
||||
@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}.
|
||||
|
||||
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
|
||||
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
|
||||
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,
|
||||
|
||||
@commandline{mzscheme -l scheme/date -i}
|
||||
@commandline{racket -l racket/date -i}
|
||||
|
||||
produces a @tech{REPL} that fails for every expression, because
|
||||
@schememodname[scheme/date] provides only a few functions, and not the
|
||||
@scheme[#%top-interaction] and @scheme[#%app] bindings that are needed
|
||||
@racketmodname[racket/date] provides only a few functions, and not the
|
||||
@racket[#%top-interaction] and @racket[#%app] bindings that are needed
|
||||
to evaluate top-level function calls in the @tech{REPL}.
|
||||
|
||||
If a module-requiring flag appears after @Flag{i}/@DFlag{repl} instead
|
||||
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,
|
||||
|
||||
@commandline{mzscheme -i -l scheme/date}
|
||||
@commandline{racket -i -l racket/date}
|
||||
|
||||
starts a useful @tech{REPL} with @schememodname[scheme/date] available
|
||||
in addition to the exports of @schememodname[scheme].
|
||||
starts a useful @tech{REPL} with @racketmodname[racket/date] available
|
||||
in addition to the exports of @racketmodname[racket].
|
||||
|
||||
@; ----------------------------------------
|
||||
|
||||
@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
|
||||
is required as a module, and (unless @Flag{i}/@DFlag{repl} is
|
||||
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
|
||||
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
|
||||
@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
|
||||
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,
|
||||
|
||||
@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
|
||||
@filepath{goodbye.ss} module, and then exits.
|
||||
requires the @filepath{hello.rkt} module, then requires the
|
||||
@filepath{goodbye.rkt} module, and then exits.
|
||||
|
||||
The @Flag{l} or @DFlag{lib} flag is similar to
|
||||
@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,
|
||||
since the @scheme[compiler] module is the main @exec{mzc}
|
||||
module.
|
||||
is the same as running the @exec{raco} executable with no arguments,
|
||||
since the @racket[raco] module is the executable's main module.
|
||||
|
||||
Note that if you wanted to pass command-line flags to
|
||||
@scheme[compiler] above, you would need to protect the flags with a
|
||||
@Flag{-}, so that @exec{mzscheme} doesn't try to parse them itself:
|
||||
@racket[raco] above, you would need to protect the flags with a
|
||||
@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}
|
||||
|
||||
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
|
||||
module file. This evaluation is like starting a @tech{REPL} and typing
|
||||
the expressions directly, except that the results are not printed.
|
||||
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
|
||||
@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
|
||||
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.
|
||||
|
||||
For file loading and expression evaluation, the top-level environment
|
||||
is created in the same way for
|
||||
@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,
|
||||
|
||||
@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
|
||||
evaluation using the smaller @schememodname[scheme/base] language,
|
||||
instead of @schememodname[scheme/init].
|
||||
evaluation using the smaller @racketmodname[racket/base] language,
|
||||
instead of @racketmodname[racket/init].
|
||||
|
||||
@; ----------------------------------------------------------------------
|
||||
|
||||
|
|
|
@ -5,13 +5,13 @@
|
|||
|
||||
@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
|
||||
same kind of scripts, or scripts can be implemented as batch files.
|
||||
|
||||
@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{#!}}
|
||||
convention. The first two characters of the file must be @litchar{#!};
|
||||
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
|
||||
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
|
||||
@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:
|
||||
|
||||
@verbatim[#:indent 2]{
|
||||
#! /usr/local/bin/mzscheme
|
||||
#lang scheme/base
|
||||
#! /usr/local/bin/racket
|
||||
#lang racket/base
|
||||
"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 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.
|
||||
|
||||
Instead of specifying a complete path to the @exec{mzscheme}
|
||||
executable, a popular alternative is to require that @exec{mzscheme}
|
||||
Instead of specifying a complete path to the @exec{racket}
|
||||
executable, a popular alternative is to require that @exec{racket}
|
||||
is in the user's command path, and then ``trampoline'' using
|
||||
@exec{/usr/bin/env}:
|
||||
|
||||
@verbatim[#:indent 2]{
|
||||
#! /usr/bin/env mzscheme
|
||||
#lang scheme/base
|
||||
#! /usr/bin/env racket
|
||||
#lang racket/base
|
||||
"Hello, world!"
|
||||
}
|
||||
|
||||
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]{
|
||||
#! /usr/bin/env mzscheme
|
||||
#lang scheme/base
|
||||
#! /usr/bin/env racket
|
||||
#lang racket/base
|
||||
(printf "Given arguments: ~s\n"
|
||||
(current-command-line-arguments))
|
||||
}
|
||||
|
||||
If the name of the script is needed, it is available via
|
||||
@scheme[(find-system-path 'run-file)], instead of via
|
||||
@scheme[(current-command-line-arguments)].
|
||||
@racket[(find-system-path 'run-file)], instead of via
|
||||
@racket[(current-command-line-arguments)].
|
||||
|
||||
Usually, then best way to handle command-line arguments is to parse
|
||||
them using the @scheme[command-line] form provided by
|
||||
@schememodname[scheme]. The @scheme[command-line] form extracts
|
||||
command-line arguments from @scheme[(current-command-line-arguments)]
|
||||
them using the @racket[command-line] form provided by
|
||||
@racketmodname[racket]. The @racket[command-line] form extracts
|
||||
command-line arguments from @racket[(current-command-line-arguments)]
|
||||
by default:
|
||||
|
||||
@verbatim[#:indent 2]{
|
||||
#! /usr/bin/env mzscheme
|
||||
#lang scheme
|
||||
#! /usr/bin/env racket
|
||||
#lang racket
|
||||
|
||||
(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
|
||||
that are comments in one language and expressions in the other. This
|
||||
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]|{
|
||||
#! /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 "bytecode files has been disabled via -c.\n")
|
||||
(printf "Given arguments: ~s\n"
|
||||
(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{#} 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
|
||||
@exec{mzscheme}.
|
||||
@exec{racket}.
|
||||
|
||||
@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:
|
||||
|
||||
@verbatim[#:indent 2]|{
|
||||
; @echo off
|
||||
; MzScheme.exe "%~f0" %*
|
||||
; Racket.exe "%~f0" %*
|
||||
; exit /b
|
||||
#lang scheme/base
|
||||
#lang racket/base
|
||||
"Hello, world!"
|
||||
}|
|
||||
|
||||
@;{
|
||||
Original trick from Ben Goetter, who used:
|
||||
|
||||
; @echo off && REM -*- scheme -*-
|
||||
; "%MZSCHEME%" "%~f0" %*
|
||||
; @echo off && REM -*- racket -*-
|
||||
; "%RACKET%" "%~f0" %*
|
||||
; exit /b
|
||||
#lang scheme
|
||||
#lang racket
|
||||
...
|
||||
|
||||
it might be worth documenting the Emacs "-*-" convention and a way to
|
||||
|
|
|
@ -33,8 +33,8 @@ The following kinds of values are serializable:
|
|||
|
||||
@itemize[
|
||||
|
||||
@item{structures created through @scheme[define-serializable-struct] or
|
||||
@scheme[define-serializable-struct/version], or more generally
|
||||
@item{structures created through @scheme[serializable-struct] or
|
||||
@scheme[serializable-struct/versions], or more generally
|
||||
structures with the @scheme[prop:serializable] property (see
|
||||
@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 ...)]{
|
||||
|
||||
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
|
||||
the top level or in a module's top level (so that deserialization
|
||||
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
|
||||
through some other mutable value).
|
||||
|
||||
In addition to the bindings generated by @scheme[define-struct],
|
||||
@scheme[define-serializable-struct] binds
|
||||
In addition to the bindings generated by @scheme[struct],
|
||||
@scheme[serializable-struct] binds
|
||||
@schemeidfont{deserialize-info:}@scheme[_id]@schemeidfont{-v0} to
|
||||
deserialization information. Furthermore, in a module context, it
|
||||
automatically @scheme[provide]s this binding.
|
||||
|
||||
The @scheme[define-serializable-struct] form enables the construction
|
||||
of structure instances from places where
|
||||
@schemeidfont{make}@scheme[id] is not accessible, since
|
||||
deserialization must construct instances. Furthermore,
|
||||
@scheme[define-serializable-struct] provides limited access to field
|
||||
The @scheme[serializable-struct] form enables the construction of
|
||||
structure instances from places where @scheme[id] is not accessible,
|
||||
since deserialization must construct instances. Furthermore,
|
||||
@scheme[serializable-struct] provides limited access to field
|
||||
mutation, but only for instances generated through the deserialization
|
||||
information bound to
|
||||
@schemeidfont{deserialize-info:}@scheme[_id]@schemeidfont{-v0}. See
|
||||
|
@ -368,9 +367,9 @@ information bound to
|
|||
|
||||
The @scheme[-v0] suffix on the deserialization enables future
|
||||
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
|
||||
include all of the supertype's field accessors. If any field mutator
|
||||
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[
|
||||
#:eval ser-eval
|
||||
(define-serializable-struct point (x y))
|
||||
(point-x (deserialize (serialize (make-point 1 2))))
|
||||
(serializable-struct point (x y))
|
||||
(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 ...)
|
||||
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
|
||||
cycle-make-proc-expr)])]{
|
||||
|
||||
Like @scheme[define-serializable-struct], but the generated
|
||||
deserializer binding is
|
||||
Like @scheme[serializable-struct], but the generated deserializer
|
||||
binding is
|
||||
@schemeidfont{deserialize-info:}@scheme[_id]@schemeidfont{-v}@scheme[vers]. In
|
||||
addition,
|
||||
@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[
|
||||
#:eval ser-eval
|
||||
(define-serializable-struct point (x y) #:mutable #:transparent)
|
||||
(define ps (serialize (make-point 1 2)))
|
||||
(serializable-struct point (x y) #:mutable #:transparent)
|
||||
(define ps (serialize (point 1 2)))
|
||||
(deserialize ps)
|
||||
|
||||
(define x (make-point 1 10))
|
||||
(define x (point 1 10))
|
||||
(set-point-x! x x)
|
||||
(define xs (serialize x))
|
||||
(deserialize xs)
|
||||
|
||||
(define-serializable-struct/versions point 1 (x y z)
|
||||
(serializable-struct/versions point 1 (x y z)
|
||||
([0
|
||||
(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:})
|
||||
(lambda ()
|
||||
(let ([p0 (make-point #f #f 0)])
|
||||
(let ([p0 (point #f #f 0)])
|
||||
(values
|
||||
p0
|
||||
(lambda (p)
|
||||
(set-point-x! p0 (point-x p))
|
||||
(set-point-y! p0 (point-y p))))))])
|
||||
#:mutable #:transparent)
|
||||
(deserialize (serialize (make-point 4 5 6)))
|
||||
(deserialize (serialize (point 4 5 6)))
|
||||
(deserialize ps)
|
||||
(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?]
|
||||
[cycle-make (-> (values any/c procedure?))])
|
||||
any]{
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
(provide all-contract-tests)
|
||||
|
||||
(require rktunit
|
||||
(require racunit
|
||||
deinprogramm/define-record-procedures
|
||||
deinprogramm/contract/contract
|
||||
deinprogramm/contract/contract-syntax)
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
(provide all-image-tests)
|
||||
|
||||
(require rktunit
|
||||
(require racunit
|
||||
deinprogramm/image
|
||||
(only-in lang/private/imageeq image=?)
|
||||
mred
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#lang scheme/base
|
||||
|
||||
(require rktunit/text-ui)
|
||||
(require racunit/text-ui)
|
||||
(require tests/deinprogramm/contract)
|
||||
|
||||
(run-tests all-contract-tests)
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#lang scheme/base
|
||||
|
||||
(require rktunit/text-ui)
|
||||
(require racunit/text-ui)
|
||||
(require tests/deinprogramm/image)
|
||||
|
||||
(run-tests all-image-tests)
|
||||
|
|
|
@ -216,7 +216,7 @@
|
|||
=> '(#"1 test passed\n" #"2 tests passed\n")
|
||||
)
|
||||
|
||||
;; RktUnit stuff
|
||||
;; RacUnit stuff
|
||||
;; (examples that should fail modified to ones that shouldn't)
|
||||
#|
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#lang scheme/base
|
||||
|
||||
(require scheme/future
|
||||
rktunit)
|
||||
racunit)
|
||||
|
||||
#|Need to add expressions which raise exceptions inside a
|
||||
future thunk which can be caught at the touch site
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#lang racket
|
||||
(require rktunit
|
||||
rktunit/text-ui
|
||||
(require racunit
|
||||
racunit/text-ui
|
||||
net/url
|
||||
(prefix-in h: html)
|
||||
(prefix-in x: xml))
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
"plot"
|
||||
"profj"
|
||||
"r6rs"
|
||||
"rktunit"
|
||||
"racunit"
|
||||
"srfi"
|
||||
"srpersist"
|
||||
"stepper"
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#lang scheme/base
|
||||
(require rktunit
|
||||
rktunit/gui)
|
||||
(require racunit
|
||||
racunit/gui)
|
||||
(require macro-debugger/model/debug
|
||||
"gentest-framework.ss"
|
||||
"gentests.ss"
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
#lang scheme/base
|
||||
(require rktunit)
|
||||
(require racunit)
|
||||
(require macro-debugger/model/debug
|
||||
macro-debugger/model/stx-util
|
||||
"gentest-framework.ss"
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
#lang scheme/base
|
||||
(require rktunit
|
||||
rktunit/gui)
|
||||
(require racunit
|
||||
racunit/gui)
|
||||
(require macro-debugger/model/debug
|
||||
scheme/path
|
||||
scheme/gui)
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
#lang scheme/base
|
||||
(require rktunit)
|
||||
(require racunit)
|
||||
(require macro-debugger/model/debug
|
||||
"../test-setup.ss")
|
||||
(provide specialized-hiding-tests)
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
#lang scheme/base
|
||||
(require rktunit)
|
||||
(require racunit)
|
||||
(require macro-debugger/model/debug
|
||||
"../test-setup.ss")
|
||||
(provide policy-tests)
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
#lang scheme/base
|
||||
(require rktunit)
|
||||
(require racunit)
|
||||
(require macro-debugger/model/debug
|
||||
macro-debugger/model/steps
|
||||
"../test-setup.ss")
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
(for-syntax scheme/base)
|
||||
(prefix-in m: mzlib/match)
|
||||
(only-in srfi/13 string-contains)
|
||||
rktunit)
|
||||
racunit)
|
||||
|
||||
(define-syntax (comp stx)
|
||||
(syntax-case stx ()
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
(module match-tests mzscheme
|
||||
(require mzlib/match rktunit)
|
||||
(require mzlib/match racunit)
|
||||
|
||||
(provide match-tests)
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
(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)
|
||||
|
||||
(define-struct shape (color))
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
(module other-tests mzscheme
|
||||
(require mzlib/match rktunit)
|
||||
(require mzlib/match racunit)
|
||||
|
||||
(provide other-tests)
|
||||
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user