From ff1189600adf28ca903c737637f6fa8651c99ec3 Mon Sep 17 00:00:00 2001 From: Matthew Flatt Date: Fri, 22 Jun 2007 12:19:03 +0000 Subject: [PATCH] doc work (fix long filename) svn: r6717 --- collects/scribble/html-render.ss | 26 ++- .../scribblings/guide/define-struct.scrbl | 187 ++++++++++++++++- .../scribblings/reference/reference.scrbl | 1 + collects/scribblings/reference/struct.scrbl | 196 ++++++++++++++++++ collects/scribblings/reference/syntax.scrbl | 2 +- 5 files changed, 392 insertions(+), 20 deletions(-) create mode 100644 collects/scribblings/reference/struct.scrbl diff --git a/collects/scribble/html-render.ss b/collects/scribble/html-render.ss index 35e94ce9aa..f454eeb8ab 100644 --- a/collects/scribble/html-render.ss +++ b/collects/scribble/html-render.ss @@ -272,12 +272,16 @@ (current-subdirectory)) (super get-dest-directory))) - (define/private (derive-filename d) - (format "~a.html" (regexp-replace* - "[^-a-zA-Z0-9_=]" - (or (format "~a" (part-tag d)) - (content->string (part-title-content d))) - "_"))) + (define/private (derive-filename d ht) + (let ([fn (format "~a.html" (regexp-replace* + "[^-a-zA-Z0-9_=]" + (or (format "~a" (part-tag d)) + (content->string (part-title-content d) + this d ht)) + "_"))]) + (when ((string-length fn) . >= . 100) + (error "file name too long (need a tag):" fn)) + fn)) (define/override (collect ds fns) (super collect ds (map (lambda (fn) @@ -297,7 +301,7 @@ 1 (add1 prev-sub))]) (if (= 1 prev-sub) - (let ([filename (derive-filename d)]) + (let ([filename (derive-filename d ht)]) (parameterize ([current-output-file (build-path (path-only (current-output-file)) filename)]) (super collect-part d parent ht number))) @@ -417,7 +421,7 @@ (make-element (if parent (make-target-url (if prev - (derive-filename prev) + (derive-filename prev ht) "index.html")) "nonavigation") prev-content) @@ -426,14 +430,14 @@ (if parent (make-target-url (if (toc-part? parent) - (derive-filename parent) + (derive-filename parent ht) "index.html")) "nonavigation") up-content) sep-element (make-element (if next - (make-target-url (derive-filename next)) + (make-target-url (derive-filename next ht)) "nonavigation") next-content)))))))) d @@ -447,7 +451,7 @@ (next-separate-page))) ;; Render as just a link, and put the actual ;; content in a new file: - (let* ([filename (derive-filename d)] + (let* ([filename (derive-filename d ht)] [full-path (build-path (path-only (current-output-file)) filename)]) (parameterize ([on-separate-page #t]) diff --git a/collects/scribblings/guide/define-struct.scrbl b/collects/scribblings/guide/define-struct.scrbl index 435c1fba6b..8aa67bd484 100644 --- a/collects/scribblings/guide/define-struct.scrbl +++ b/collects/scribblings/guide/define-struct.scrbl @@ -39,13 +39,13 @@ are built from @scheme[_struct-id] and the @scheme[_field-id]s: @itemize{ @item{@schemeidfont{make-}@scheme[_struct-id] : a - @defterm{constructor} function that takes as many arguments as + @deftech{constructor} function that takes as many arguments as the number of @scheme[_field-id]s, and returns an instance of the structure type. @examples[(make-posn 1 2)]} - @item{@scheme[_struct-id]@schemeidfont{?} : a @defterm{predicate} + @item{@scheme[_struct-id]@schemeidfont{?} : a @deftech{predicate} function that takes a single argument and returns @scheme[#t] if it is an instance of the structure type, @scheme[#f] otherwise. @@ -53,14 +53,14 @@ are built from @scheme[_struct-id] and the @scheme[_field-id]s: @examples[(posn? 3) (posn? (make-posn 1 2))]} @item{@scheme[_struct-id]@schemeidfont{-}@scheme[_field-id] : for - each @scheme[_field-id], an @defterm{accessor} that extracts + each @scheme[_field-id], an @deftech{accessor} that extracts the value of the corresponding field from an instance of the structure type. @examples[(posn-x (make-posn 1 2)) (posn-y (make-posn 1 2))]} @item{@schemeidfont{set-}@scheme[_struct-id]@schemeidfont{-}@scheme[_field-id]@schemeidfont{!} : for - each @scheme[_field-id], a @defterm{mutator} that sets + each @scheme[_field-id], a @deftech{mutator} that sets the value of the corresponding field in an instance of the structure type. @@ -68,6 +68,12 @@ are built from @scheme[_struct-id] and the @scheme[_field-id]s: (posn-x p) (set-posn-x! p 10) (posn-x p)]} + + @item{@schemeidfont{struct:}@scheme[_struct-id] : a + @deftech{structure type descriptor}, which is a value that + represents the structure type (as opposed to a single instance) + for certain reflective operations.} + } A @scheme[define-struct] form places no constraints on the kinds of @@ -76,7 +82,7 @@ type. For example, @scheme[(make-posn "apple" #f)] produces an instance of @scheme[posn], even though @scheme["apple"] and @scheme[#f] are not valid coordinates for the obvious uses of @scheme[posn] instances. Enforcing constraints on field values, such -as requiring them to be numbers, is the job of a contract, as +as requiring them to be numbers, is normally the job of a contract, as discussed later in @secref["guide:contracts"]. @; ------------------------------------------------------------ @@ -114,7 +120,7 @@ p ] @; ------------------------------------------------------------ -@section{Opaque versus Transparent Stucture Types} +@section[#:tag "guide:trans-struct"]{Opaque versus Transparent Stucture Types} With a structure type definition like @@ -141,11 +147,176 @@ field-name sequence: An instance of a transparent structure type prints like a vector, and it shows the content of the structure's fields. A transparent structure type also allows reflective operations, like -@scheme[struct?] and @scheme[struct-info], to be used on its -instances (see @secref["reflection"]). +@scheme[struct?] and @scheme[struct-info], to be used on its instances +(see @secref["reflection"]). Different values for @scheme[#:inspector] +support more controlled access to reflective operations. Structure types are opaque by default, because opaque structure instances provide more encapsulation guarantees. That is, a library can use an opaque structure to encapsulate data, and clients of the library cannot manipulate the data in the structure except as allowed by the library. + +@; ------------------------------------------------------------ +@section{More Structure Type Options} + +The full syntax of @scheme[define-struct] supports many options, both +at the structure-type level and at the level of individual fields: + +@specform/subs[(define-struct id-maybe-super (field ...) + struct-option ...) + ([id-maybe-super struct-id + (struct-id super-id)] + [field field-id + [field-id field-option ...]])] + +A @scheme[_struct-option] always starts with a keyword: + + @specspecsubform[#:immutable]{ + + Causes all fields of the structure type to be immutable, and + supresses the definition of @tech{mutator} procedures. + + @defexamples[(define-struct fixed-posn (x y) #:immutable) + (set-fixed-posn-x! (make-fixed-posn 1 2) 0)] + + Th @scheme[#:immutable] option can also be used as a + @scheme[_field-option], in which case it makes an individual field + immutable. + + @defexamples[ + (define-struct person ([name #:immutable] age)) + (define friend (make-person "Barney" 5)) + (set-person-age! friend 6) + (set-person-name! friend "Mary")]} + + @specspecsubform[(code:line #:inspector inspector-expr)]{ + Controls reflective access to structure instances, as discussed + in the previous section (@secref["guide:trans-struct"]). + } + + @specspecsubform[(code:line #:auto-value auto-expr)]{ + + Specifies a value to be used for all automatic fields in the + structure type, where an automatic field is indicated by the + @scheme[#:auto] @scheme[_field-option]. The structure type's + constructor omits arguments for automatic fields. + + @defexamples[ + (define-struct posn (x y [z #:auto]) + #:inspector #f + #:auto-value 0) + (make-posn 1 2) + ]} + + @specspecsubform[(code:line #:guard guard-expr)]{ + Specifies a guard procedure to be called whenever an instance of + the structure type is created. The guard takes as many arguments + as non-automatic fields in the structure type, and it should return + the same number of values. The guard can raise an exception if one + of the given arguments is unacceptable, or it can convert an + argument. + + @defexamples[ + (define-struct thing (name) + #:inspector #f + #:guard (lambda (name type-name) + (cond + [(string? name) name] + [(number? name) + (number->string name)] + [else (error "bad name" name)]))) + (make-thing "apple") + (make-thing 1/2) + (make-thing #f)] + + Unlike the constructor for a procedure type, the guard is called even when + subtype instances are created. In that case, only the fields accepted by + the constructor are provided to the guard (but the subtype's guard gets + both the original fields and fields added by the subtype). + + @defexamples[ + (define-struct (person thing) (age) + #:inspector #f + #:guard (lambda (name age type-name) + (if (negative? age) + (error "bad age" age) + (values name age)))) + (make-person "John" 10) + (make-person "Mary" -1) + (make-person #f 10)]} + + @specspecsubform[(code:line #:property prop-expr val-exr)]{ + Associates a property and value with the structure type. For + example, the @scheme[prop:procedure] property allows a structure + instance to be used as a function; the property value determines + how a call is implemented when using the structure as a function. + + @defexamples[ + (define-struct greeter (name) + #:property prop:procedure + (lambda (self other) + (string-append + "Hi " other + ", I'm " (greeter-name self)))) + (define joe-greet (make-greeter "Joe")) + (greeter-name joe-greet) + (joe-greet "Mary") + (joe-greet "John")]} + + @specspecsubform[(code:line #:super super-expr)]{ + + An alternative to supplying a @scheme[super-id] next to + @scheme[struct-id]. Instead of the name of a structure type (which is + not an expression), @scheme[super-expr] should produce a + @tech{structure type descriptor} value. An advantage of + @scheme[#:super] is that structure type descriptors are values, so + they can be passed to procedures. + + @defexamples[ + (define (make-raven-constructor super-type) + (define-struct raven () + #:super super-type + #:inspector #f + #:property prop:procedure (lambda (self) + 'nevermore)) + make-raven) + (let ([r ((make-raven-constructor struct:posn) 1 2)]) + (list r (r))) + (let ([r ((make-raven-constructor struct:thing) "apple")]) + (list r (r)))]} + + +@; ------------------------------------------------------------ +@section{Structure Type Generativity} + +Each time that a @scheme[define-struct] form is evaluated, it +generates a structure type that is distinct from all existing +structure types, even if some other structure type has the same name +and fields. + +This generativity is useful for enforcing abstractions and +implementing programs such as interpreters, but beware of placing a +@scheme[define-struct] form in positions that are evaluated multiple +times. + +@defexamples[ +(define (add-bigger-fish lst) + (define-struct fish (size) #:inspector #f) + (cond + [(null? lst) (list (make-fish 1))] + [else (cons (make-fish (* 2 (fish-size (car lst)))) + lst)])) + +(add-bigger-fish null) +(add-bigger-fish (add-bigger-fish null)) +] +@defs+int[ +[(define-struct fish (size) #:inspector #f) + (define (add-bigger-fish lst) + (cond + [(null? lst) (list (make-fish 1))] + [else (cons (make-fish (* 2 (fish-size (car lst)))) + lst)]))] +(add-bigger-fish (add-bigger-fish null)) +] diff --git a/collects/scribblings/reference/reference.scrbl b/collects/scribblings/reference/reference.scrbl index 30ccc6ba1b..e6f11aa7f5 100644 --- a/collects/scribblings/reference/reference.scrbl +++ b/collects/scribblings/reference/reference.scrbl @@ -17,6 +17,7 @@ language. @include-section["syntax.scrbl"] @include-section["derived.scrbl"] @include-section["data.scrbl"] +@include-section["struct.scrbl"] @;------------------------------------------------------------------------ diff --git a/collects/scribblings/reference/struct.scrbl b/collects/scribblings/reference/struct.scrbl new file mode 100644 index 0000000000..6b77c1274d --- /dev/null +++ b/collects/scribblings/reference/struct.scrbl @@ -0,0 +1,196 @@ +#reader(lib "docreader.ss" "scribble") +@require["mz.ss"] + +@title[#:tag "mz:structures"]{Structures} + +A @pidefterm{structure type} is a record datatype composing a number +of @idefterm{fields}. A @pidefterm{structure}, an instance of a +structure type, is a first-class value that contains a value for each +field of the structure type. A structure instance is created with a +type-specific @tech{constructor} procedure, and its field values are +accessed and changed with type-specific @tech{accessor} and +@tech{mutator} procedures. In addition, each structure type has a +@tech{predicate} procedure that answers @scheme[#t] for instances of +the structure type and @scheme[#f] for any other value. + +A structure type's fields are essentially unnamed, though names are +supported for error-reporting purposes. The constructor procedure +takes one value for each field of the structure type, except that some +of the fields of a structure type can be @deftech{automatic fields}; +the @tech{automatic fields} are initialized to a constant that is +associated with the structure type, and the corresponding arguments +are omitted for the constructor procedure. All automatic fields in a +structure type follow the non-automatic fields. + +A structure type can be created as a @pidefterm{structure subtype} of +an existing base structure type. An instance of a structure subtype +can always be used as an instance of the base structure type, but the +subtype gets its own predicate procedure, and it may have its own +fields in addition to the fields of the base type. + +A structure subtype ``inherits'' the fields of its base type. If the +base type has @math{m} fields, and if @math{n} fields are specified +for the new structure subtype, then the resulting structure type has +@math{m+n} fields. The value for automatic fields can be different in +a subtype than in its base type. + +If @math{m'} of the original @math{m} fields are non-automatic (where +@math{m'symbol (format "make-~a" name)) + "second field must be a number")) + (values a1 (exact->inexact a2) b1)))) +(make-c 'x 'y 'z) +(define a-c (make-c 'x 2 'z)) +(a-ref a-c 1) +]} + +@defproc[(make-struct-field-accessor [accessor-proc procedure?] + [field-pos-k exact-nonnegative-integer?] + [field-name symbol?]) + procedure?]{ + +Returns a field accessor that is equivalent to @scheme[(lambda (s) +(accessor-proc s field-pos-k))]. The @scheme[accessor-proc] must be +an @tech{accessor} returned by @scheme[make-struct-type]. The name of the +resulting procedure for debugging purposes is derived from +@scheme[field-name] and the name of @scheme[accessor-proc]'s +structure type. + +For examples, see @scheme[make-struct-type].} + +@defproc[(make-struct-field-mutator [mutator-proc procedure?] + [field-pos-k exact-nonnegative-integer?] + [field-name symbol?]) + procedure?]{ + +Returns a field mutator that is equivalent to @scheme[(lambda (s v) +(mutator-proc s field-pos-k v))]. The @scheme[mutator-proc] must be +a @tech{mutator} returned by @scheme[make-struct-type]. The name of the +resulting procedure for debugging purposes is derived from +@scheme[field-name] and the name of @scheme[mutator-proc]'s +structure type. + +For examples, see @scheme[make-struct-type].} diff --git a/collects/scribblings/reference/syntax.scrbl b/collects/scribblings/reference/syntax.scrbl index d9160b502a..55f61c113e 100644 --- a/collects/scribblings/reference/syntax.scrbl +++ b/collects/scribblings/reference/syntax.scrbl @@ -354,7 +354,7 @@ Like @scheme[lambda], but without support for keyword or optional arguments. } @;------------------------------------------------------------------------ -@section{Local Binding: @scheme[let], @scheme[let*], and @scheme[letrec]} +@section[#:tag "mz:let"]{Local Binding: @scheme[let], @scheme[let*], and @scheme[letrec]} @defform*[[(let ([id val-expr] ...) body ...+) (let proc-id ([id init-expr] ...) body ...+)]]{