xlist.scrbl (13358B)
1 #lang scribble/manual 2 @require[scribble-enhanced/with-manual 3 xlist/scribble-enhanced 4 scribble-math 5 racket/require 6 @for-label[xlist 7 (subtract-in typed/racket/base match-string) 8 (only-in syntax/parse ...+) 9 match-string]] 10 11 @title[#:style (with-html5 manual-doc-style)]{xlist} 12 @author[@author+email["Suzanne Soy" "racket@suzanne.soy"]] 13 14 @(define ddd (racket ...)) 15 16 @defmodule[xlist] 17 18 Fancy lists, with bounded or unbounded repetition of elements. Can be used as a 19 type or match pattern. 20 21 To use the type expander, you must first require the 22 @racketmodname[type-expander] library. 23 24 @deftogether[ 25 [@defform*[#:kind "type-expander" 26 [(xList τᵢ ...) 27 (xList τᵢ ... . rest) 28 (xList τᵢ ... #:rest rest)]] 29 @defform*[#:kind "type-expander" 30 #:literals (^ * + - ∞ once) 31 [(xlist τᵢ ...) 32 (xlist τᵢ ... . rest) 33 (xlist τᵢ ... #:rest rest)] 34 #:grammar 35 [(τᵢ type 36 repeated-type) 37 (repeated-type (code:line type ^ repeat) 38 (code:line type ^ {repeat}) 39 (code:line type {repeat}) 40 (code:line type superscripted-repeat) 41 (code:line type *) 42 (code:line type +) 43 (code:line superscripted-id)) 44 (repeat (code:line once) 45 (code:line nat) 46 (code:line nat +) 47 (code:line +) 48 (code:line nat - nat) 49 (code:line nat - ∞) 50 (code:line nat -) 51 (code:line - nat) 52 (code:line -) 53 (code:line - ∞) 54 (code:line *))] 55 #:contracts 56 [(nat (syntax/c exact-nonnegative-integer?))]]]]{ 57 The notation @racket[type ^ _n], where @racket[_n] is a number, indicates that 58 the given type should be repeated @racket[_n] times within the list. Therefore, 59 the following two types are equivalent: 60 61 @racketblock[ 62 (xList Number ^ 3 Symbol String ^ 2) 63 64 (List Number Number Number Symbol String String)] 65 66 The notation @racket[type *] indicates that the given type may be repeated zero 67 or more times. Therefore, the following two types are equivalent: 68 69 @racketblock[ 70 (xList Number * Symbol String *) 71 72 (Rec R1 (U (Pairof Number R1) 73 (List* Symbol (Rec R2 (U (Pairof String R2) 74 Null)))))] 75 76 The notation @racket[type ^ _n +] indicates that the given type may be repeated 77 @racket[_n] or more times. Therefore, the following two types are equivalent: 78 79 @racketblock[ 80 (xList Number ^ {2 +} String) 81 82 (List* Number Number (Rec R1 (U (Pairof Number R1) 83 (List String))))] 84 85 When the number preceding @racket[+] is omitted, it defaults to @racket[1]. 86 87 The notation @racket[type ^ once] yields the same type as @racket[type ^ 1], 88 but other forms recognise @racket[once] and treat it specially. For example, 89 @racket[xlist-split] splits the corresponding element as a standalone value, 90 not as a list of length one. 91 92 The notation @racket[type ^ _n - _m] indicates that the given type may be 93 repeated between @racket[_n] (inclusive) and @racket[_m] (inclusive) times. 94 Therefore, the following two types are equivalent: 95 96 @racketblock[ 97 (xList Number ^ {2 - 5} String) 98 99 (U (List Number Number String) 100 (List Number Number Number String) 101 (List Number Number Number Number String) 102 (List Number Number Number Number Number String))] 103 104 Be aware that the tail of the @racket[xList] following the use of 105 @racket[type ^ _n - _m] is repeated @${n - m} times, so if the tail itself 106 contains uses of @racket[-], the resulting macro-expanded type will be huge, 107 and may easily make Typed/Racket run out of memory, or slow down the type 108 checking. 109 110 If the first bound is omitted, it defaults to @racket[0], and if the second 111 bound is omitted, it defaults to @racket[∞]. This means that @racket[-] on its 112 own is equivalent to @racket[*], but the latter form is preferred. 113 114 The @racket[superscripted-repeat] is a representation of @racket[repeat] using 115 superscripted unicode characters, without spaces (i.e. the 116 @racket[superscripted-repeat] is a single identifier): 117 118 @itemlist[ 119 @item{Digits are replaced by their unicode superscripted counterparts 120 @elem[#:style 'tt "⁰¹²³⁴⁵⁶⁷⁸⁹"]} 121 @item{@racket[+] and @racket[-] are replaced by their unicode superscripted 122 counterparts, respectively @elem[#:style 'tt "⁺"] and @elem[#:style 'tt "⁻"]} 123 @item{@racket[*] is replaced by the unicode character ``COMBINING ASTERISK 124 ABOVE'' @tt{ ⃰} (code point U+20F0)} 125 @item{@racket[∞] is always omitted, as @racket[_n - ∞] and @racket[- ∞] are 126 equivalent to @racket[_n -] and @racket[0 -]}] 127 128 A @racket[superscripted-id] is a type identifier ending with a sequence of 129 characters which would otherwise be valid for @racket[superscripted-repeat]. In 130 other words, if the @racket[type] is an identifier, the type and the 131 @racket[superscripted-repeat] can be coalesced into a single identifier. 132 133 The identifier @racket[String³] is equivalent to the notations 134 @racket[String ³] (with a space between the identifier and the @racket[³]) and 135 @racket[String ^ 3]. 136 137 Similarly, the identifier @racket[String⃰] is equivalent to the notations 138 @racket[String ⃰] (with a space between the identifier and the @racket[ ⃰]), 139 @racket[String ^ *] (using a regular asterisk, i.e. the multiplication function 140 in Racket) and @racket[String *] (using a regular asterisk, i.e. the 141 multiplication function in Racket). 142 143 The same logic applies to the other cases.} 144 145 @defform*[#:kind "match-expander" 146 #:link-target? #f 147 #:literals (^ * + - ...+ ∞) 148 [(xlist patᵢ ...) 149 (xlist patᵢ ... . rest) 150 (xlist patᵢ ... #:rest rest)] 151 #:grammar 152 [(patᵢ pattern-or-spliced 153 repeated-pattern 154 spliced-pattern) 155 (pattern-or-spliced pattern 156 spliced-pattern) 157 (spliced-pattern ,@pattern) 158 (repeated-pattern (code:line pattern-or-spliced ^ repeat) 159 (code:line pattern-or-spliced ^ {repeat}) 160 (code:line pattern-or-spliced superscripted-repeat) 161 (code:line pattern-or-spliced *) 162 (code:line pattern-or-spliced +) 163 (code:line pattern-or-spliced ooo) 164 (code:line superscripted-id)) 165 (repeat (code:line once) 166 (code:line nat) 167 (code:line nat +) 168 (code:line +) 169 (code:line nat - nat) 170 (code:line nat - ∞) 171 (code:line nat -) 172 (code:line - nat) 173 (code:line - ∞) 174 (code:line -) 175 (code:line *) 176 (code:line ooo)) 177 (ooo #,ddd 178 ..k 179 ____ 180 ___k 181 ...+)] 182 #:contracts 183 [(nat (syntax/c exact-nonnegative-integer?))]]{ 184 185 This match expander works like the @racket[xList] type expander, but instead 186 controls the repetition of match patterns. The repeated patterns are not 187 literally copied, as this would likely cause errors related to duplicate 188 attributes. Instead, the @racket[repeat] forms control the number of times a 189 pattern may be bound, like @racket[...] does. 190 191 If the @racket[_repeat] is @racket[once], or if the pattern does not have a 192 @racket[_repeat], then the pattern is not put under ellipses, so that 193 @racket[(match '(42) [(xlist a ^ once) a])] returns @racket[42], whereas 194 @racket[(match '(42) [(xlist a ^ 1) a])] returns @racket['(42)]. 195 196 For convenience and compatibility with existing match patterns, the following 197 equivalences are provided: 198 @itemlist[ 199 @item{@racket[...] is equivalent to @racket[*]} 200 @item{@racket[_..k] is equivalent to @racket[_k +]} 201 @item{@racket[____] is equivalent to @racket[*]} 202 @item{@racket[___k] is equivalent to @racket[_k +]} 203 @item{@racket[...+] is equivalent to @racket[+]}] 204 205 Additionally, when @RACKET[#,@pattern] appears as one of the @racket[xlist] 206 elements, the given @racket[pattern] may match any number of elements in the 207 list. This is implemented in terms of @racket[append] from the 208 @racketmodname[match-string] library. 209 210 The following two match patterns are therefore equivalent: 211 212 @racketblock[ 213 (xlist number?³⁻⁵ ,@(list-no-order number? string?) symbol?⁺) 214 215 (append (and (list number? ...) (app length (? (between/c 3 5)))) 216 (list-no-order number? string?) 217 (list symbol? ..1))] 218 219 Applying a repeat indicator on a splice is not supported yet, i.e. 220 @racket[(xlist ,@(list-no-order number? string?)⁵)] will not work. 221 222 @emph{Note :} Typed/Racket's type inference is not strong enough (yet) to 223 support some match patterns, and there is no @elem[#:style 'tt "typed/match"] 224 library which would help with that (yet). This means that although by 225 construction @racket[xlist] tries to avoid generating such patterns, a few of 226 the patterns supported by @racket[xlist] will not work in 227 @racketmodname[typed/racket] (rest values and spliced lists are the most 228 likely to cause problems). As an alternative, try the @racket[split-xlist] 229 pattern, which produces code which should propagate type information to the 230 different sub-lists.} 231 232 @;{This is completely wrong. 233 @defform*[#:link-target? #f 234 #:literals (^ *) 235 [(xlist τᵢ ... maybe-τⱼ τₖ ... maybe-τₙ) 236 (xlist τᵢ ... τₘᵥ)] 237 #:grammar 238 [(τᵢ type 239 fixed-repeated-type) 240 (τₘᵥ mandatory-variadic-repeated-type) 241 (maybe-τⱼ (code:line) 242 mandatory-bounded-variadic-repeated-type) 243 (τₖ optional-bounded-variadic-repeated-type) 244 (maybe-τₙ (code:line) 245 optional-variadic-repeated-type) 246 (fixed-repeated-type 247 (code:line type ^ fixed-repeat) 248 (code:line type ^ {fixed-repeat}) 249 (code:line type {fixed-repeat}) 250 (code:line type superscripted-fixed-repeat) 251 (code:line superscripted-fixed-id)) 252 (mandatory-bounded-variadic-repeated-type 253 (code:line type ^ mandatory-bounded-variadic-repeat) 254 (code:line type ^ {mandatory-bounded-variadic-repeat}) 255 (code:line type {mandatory-bounded-variadic-repeat}) 256 (code:line type superscripted-mandatory-bounded-variadic-repeat) 257 (code:line superscripted-mandatory-bounded-variadic-id)) 258 (optional-bounded-variadic-repeated-type 259 (code:line type ^ optional-bounded-variadic-repeat) 260 (code:line type ^ {optional-bounded-variadic-repeat}) 261 (code:line type {optional-bounded-variadic-repeat}) 262 (code:line type superscripted-optional-bounded-variadic-repeat) 263 (code:line superscripted-optional-bounded-variadic-id)) 264 (mandatory-variadic-repeated-type 265 (code:line type ^ mandatory-variadic-repeat) 266 (code:line type ^ {mandatory-variadic-repeat}) 267 (code:line type {mandatory-variadic-repeat}) 268 (code:line type superscripted-mandatory-variadic-repeat) 269 (code:line superscripted-mandatory-variadic-id) 270 (code:line type +)) 271 (optional-variadic-repeated-type 272 (code:line type ^ optional-variadic-repeat) 273 (code:line type ^ {optional-variadic-repeat}) 274 (code:line type {optional-variadic-repeat}) 275 (code:line type superscripted-optional-variadic-repeat) 276 (code:line superscripted-optional-variadic-id) 277 (code:line type *)) 278 (fixed-repeat (code:line nat) 279 (code:line from - to (code:comment "from = to"))) 280 (mandatory-bounded-variadic-repeat (code:line nat - nat)) 281 (optional-bounded-variadic-repeat (code:line 0 - nat) 282 (code:line - nat)) 283 (mandatory-variadic-repeat (code:line nat +) 284 (code:line +) 285 (code:line nat -) 286 (code:line nat - ∞)) 287 (optional-variadic-repeat (code:line 0 - ∞) 288 (code:line 0 -) 289 (code:line - ∞) 290 (code:line -) 291 (code:line *))]]{ 292 Macro form which returns a builder function for a list with the given type. 293 The simplified syntax compared to @racket[xList] is due to the fact that there 294 are some function types that Typed/Racket cannot express (yet).} 295 } 296 297 @defproc[(normalize-xlist-type [stx syntax?] [context syntax?]) syntax?]{ 298 Normalizes the xlist type. The normalized form has one type followed by ^ 299 followed by a repeat within braces (a @racket[type] without a repeat is 300 transformed into @racket[type ^ {once}]) for each position in the original 301 type. It always finishes with #:rest rest-type. This function also performs a 302 few simplifications on the type, like transforming @racket[^ {3 -}] into 303 @racket[^ {3 +}], and transforming @racket[^ {0 -}] into @racket[^ {*}].} 304 305 @include-section{split-xlist.scrbl} 306 @include-section{xlist-untyped.scrbl} 307 @include-section{identifiers.scrbl}