]> gitweb.factorcode.org Git - factor.git/blob - core/combinators/combinators-docs.factor
Documentation updates
[factor.git] / core / combinators / combinators-docs.factor
1 USING: arrays help.markup help.syntax strings sbufs vectors
2 kernel quotations generic generic.standard classes
3 math assocs sequences sequences.private combinators.private
4 effects words ;
5 IN: combinators
6
7 ARTICLE: "cleave-shuffle-equivalence" "Expressing shuffle words with cleave combinators"
8 "Cleave combinators are defined in terms of shuffle words, and mappings from certain shuffle idioms to cleave combinators are discussed in the documentation for " { $link bi } ", " { $link 2bi } ", " { $link 3bi } ", " { $link tri } ", " { $link 2tri } " and " { $link 3tri } "."
9 $nl
10 "Certain shuffle words can also be expressed in terms of the cleave combinators. Internalizing such identities can help with understanding and writing code using cleave combinators:"
11 { $code
12     ": keep  [ ] bi ;"
13     ": 2keep [ ] 2bi ;"
14     ": 3keep [ ] 3bi ;"
15     ""
16     ": dup   [ ] [ ] bi ;"
17     ": 2dup  [ ] [ ] 2bi ;"
18     ": 3dup  [ ] [ ] 3bi ;"
19     ""
20     ": tuck  [ nip ] [ ] 2bi ;"
21     ": swap  [ nip ] [ drop ] 2bi ;"
22     ""
23     ": over  [ ] [ drop ] 2bi ;"
24     ": pick  [ ] [ 2drop ] 3bi ;"
25     ": 2over [ ] [ drop ] 3bi ;"
26 } ;
27
28 ARTICLE: "cleave-combinators" "Cleave combinators"
29 "The cleave combinators apply multiple quotations to a single value."
30 $nl
31 "Two quotations:"
32 { $subsection bi }
33 { $subsection 2bi }
34 { $subsection 3bi }
35 "Three quotations:"
36 { $subsection tri }
37 { $subsection 2tri }
38 { $subsection 3tri }
39 "An array of quotations:"
40 { $subsection cleave }
41 { $subsection 2cleave }
42 { $subsection 3cleave }
43 "Technically, the cleave combinators are redundant because they can be simulated using shuffle words and other combinators, and in addition, they do not reduce token counts by much, if at all. However, they can make code more readable by expressing intention and exploiting any inherent symmetry. For example, a piece of code which performs three operations on the top of the stack can be written in one of two ways:"
44 { $code
45     "! First alternative; uses keep"
46     "[ 1 + ] keep"
47     "[ 1 - ] keep"
48     "2 *"
49     "! Second alternative: uses tri"
50     "[ 1 + ]"
51     "[ 1 - ]"
52     "[ 2 * ] tri"
53 }
54 "The latter is more aesthetically pleasing than the former."
55 { $subsection "cleave-shuffle-equivalence" } ;
56
57 ARTICLE: "spread-shuffle-equivalence" "Expressing shuffle words with spread combinators"
58 "Spread combinators are defined in terms of shuffle words, and mappings from certain shuffle idioms to spread combinators are discussed in the documentation for " { $link bi* } ", " { $link 2bi* } ", " { $link tri* } ", and " { $link 2tri* } "."
59 $nl
60 "Certain shuffle words can also be expressed in terms of the spread combinators. Internalizing such identities can help with understanding and writing code using spread combinators:"
61 { $code
62     ": dip   [ ] bi* ;"
63     ": 2dip  [ ] [ ] tri* ;"
64     ""
65     ": slip  [ call ] [ ] bi* ;"
66     ": 2slip [ call ] [ ] [ ] tri* ;"
67     ""
68     ": nip   [ drop ] [ ] bi* ;"
69     ": 2nip  [ drop ] [ drop ] [ ] tri* ;"
70     ""
71     ": rot"
72     "    [ [ drop ] [      ] [ drop ] tri* ]"
73     "    [ [ drop ] [ drop ] [      ] tri* ]"
74     "    [ [      ] [ drop ] [ drop ] tri* ]"
75     "    3tri ;"
76     ""
77     ": -rot"
78     "    [ [ drop ] [ drop ] [      ] tri* ]"
79     "    [ [      ] [ drop ] [ drop ] tri* ]"
80     "    [ [ drop ] [      ] [ drop ] tri* ]"
81     "    3tri ;"
82     ""
83     ": spin"
84     "    [ [ drop ] [ drop ] [      ] tri* ]"
85     "    [ [ drop ] [      ] [ drop ] tri* ]"
86     "    [ [      ] [ drop ] [ drop ] tri* ]"
87     "    3tri ;"
88 } ;
89
90 ARTICLE: "spread-combinators" "Spread combinators"
91 "The spread combinators apply multiple quotations to multiple values. The " { $snippet "*" } " suffix signifies spreading."
92 $nl
93 "Two quotations:"
94 { $subsection bi* }
95 { $subsection 2bi* }
96 "Three quotations:"
97 { $subsection tri* }
98 { $subsection 2tri* }
99 "An array of quotations:"
100 { $subsection spread }
101 "Technically, the spread combinators are redundant because they can be simulated using shuffle words and other combinators, and in addition, they do not reduce token counts by much, if at all. However, they can make code more readable by expressing intention and exploiting any inherent symmetry. For example, a piece of code which performs three operations on three related values can be written in one of two ways:"
102 { $code
103     "! First alternative; uses dip"
104     "[ [ 1 + ] dip 1 - ] dip 2 *"
105     "! Second alternative: uses tri*"
106     "[ 1 + ] [ 1 - ] [ 2 * ] tri*"
107 }
108 "A generalization of the above combinators to any number of quotations can be found in " { $link "combinators" } "."
109 { $subsection "spread-shuffle-equivalence" } ;
110
111 ARTICLE: "apply-combinators" "Apply combinators"
112 "The apply combinators apply a single quotation to multiple values. The " { $snippet "@" } " suffix signifies application."
113 $nl
114 "Two quotations:"
115 { $subsection bi@ }
116 { $subsection 2bi@ }
117 "Three quotations:"
118 { $subsection tri@ }
119 { $subsection 2tri@ }
120 "A pair of utility words built from " { $link bi@ } ":"
121 { $subsection both? }
122 { $subsection either? } ;
123
124 ARTICLE: "slip-keep-combinators" "Retain stack combinators"
125 "Sometimes an additional storage area is needed to hold objects. The " { $emphasis "retain stack" } " is an auxilliary stack for this purpose. Objects can be moved between the data and retain stacks using a set of combinators."
126 $nl
127 "The dip combinators invoke the quotation at the top of the stack, hiding the values underneath:"
128 { $subsection dip }
129 { $subsection 2dip }
130 { $subsection 3dip }
131 { $subsection 4dip }
132 "The slip combinators invoke a quotation further down on the stack. They are most useful for implementing other combinators:"
133 { $subsection slip }
134 { $subsection 2slip }
135 { $subsection 3slip }
136 "The keep combinators invoke a quotation which takes a number of values off the stack, and then they restore those values:"
137 { $subsection keep }
138 { $subsection 2keep }
139 { $subsection 3keep } ;
140
141 ARTICLE: "curried-dataflow" "Curried dataflow combinators"
142 "Curried cleave combinators:"
143 { $subsection bi-curry }
144 { $subsection tri-curry }
145 "Curried spread combinators:"
146 { $subsection bi-curry* }
147 { $subsection tri-curry* }
148 "Curried apply combinators:"
149 { $subsection bi-curry@ }
150 { $subsection tri-curry@ }
151 { $see-also "dataflow-combinators" } ;
152
153 ARTICLE: "compositional-examples" "Examples of compositional combinator usage"
154 "Consider printing the same message ten times:"
155 { $code ": print-10 ( -- ) 10 [ \"Hello, world.\" print ] times ;" }
156 "if we wanted to abstract out the message into a parameter, we could keep it on the stack between iterations:"
157 { $code ": print-10 ( message -- ) 10 [ dup print ] times drop ;" }
158 "However, keeping loop-invariant values on the stack doesn't always work out nicely. For example, a word to subtract a value from each element of a sequence:"
159 { $code ": subtract-n ( seq n -- seq' ) swap [ over - ] map nip ;" }
160 "Three shuffle words are required to pass the value around. Instead, the loop-invariant value can be partially applied to a quotation using " { $link curry } ", yielding a new quotation that is passed to " { $link map } ":"
161 { $example
162   "USING: kernel math prettyprint sequences ;"
163   ": subtract-n ( seq n -- seq' ) [ - ] curry map ;"
164   "{ 10 20 30 } 5 subtract-n ."
165   "{ 5 15 25 }"
166 }
167 "Now consider the word that is dual to the one above; instead of subtracting " { $snippet "n" } " from each stack element, it subtracts each element from " { $snippet "n" } "."
168 $nl
169 "One way to write this is with a pair of " { $link swap } "s:"
170 { $code ": n-subtract ( n seq -- seq' ) swap [ swap - ] curry map ;" }
171 "Since this pattern comes up often, " { $link with } " encapsulates it:"
172 { $example
173   "USING: kernel math prettyprint sequences ;"
174   ": n-subtract ( n seq -- seq' ) [ - ] with map ;"
175   "30 { 10 20 30 } n-subtract ."
176   "{ 20 10 0 }"
177 }
178 { $see-also "fry.examples" } ;
179
180 ARTICLE: "compositional-combinators" "Compositional combinators"
181 "Certain combinators transform quotations to produce a new quotation."
182 { $subsection "compositional-examples" }
183 "Fundamental operations:"
184 { $subsection curry }
185 { $subsection compose }
186 "Derived operations:"
187 { $subsection 2curry }
188 { $subsection 3curry }
189 { $subsection with }
190 { $subsection prepose }
191 "These operations run in constant time, and in many cases are optimized out altogether by the " { $link "compiler" } ". " { $link "fry" } " are an abstraction built on top of these operations, and code that uses this abstraction is often clearer than direct calls to the below words."
192 $nl
193 "Curried dataflow combinators can be used to build more complex dataflow by combining cleave, spread and apply patterns in various ways."
194 { $subsection "curried-dataflow" }
195 "Quotations also implement the sequence protocol, and can be manipulated with sequence words; see " { $link "quotations" } ". However, such runtime quotation manipulation will not be optimized by the optimizing compiler." ;
196
197 ARTICLE: "booleans" "Booleans"
198 "In Factor, any object that is not " { $link f } " has a true value, and " { $link f } " has a false value. The " { $link t } " object is the canonical true value."
199 { $subsection f }
200 { $subsection t }
201 "There are some logical operations on booleans:"
202 { $subsection >boolean }
203 { $subsection not }
204 { $subsection and }
205 { $subsection or }
206 { $subsection xor }
207 "Boolean values are most frequently used for " { $link "conditionals" } "."
208 { $heading "The f object and f class" }
209 "The " { $link f } " object is the unique instance of the " { $link f } " class; the two are distinct objects. The latter is also a parsing word which adds the " { $link f } " object to the parse tree at parse time. To refer to the class itself you must use " { $link POSTPONE: POSTPONE: } " or " { $link POSTPONE: \ } " to prevent the parsing word from executing."
210 $nl
211 "Here is the " { $link f } " object:"
212 { $example "f ." "f" }
213 "Here is the " { $link f } " class:"
214 { $example "\\ f ." "POSTPONE: f" }
215 "They are not equal:"
216 { $example "f \\ f = ." "f" }
217 "Here is an array containing the " { $link f } " object:"
218 { $example "{ f } ." "{ f }" }
219 "Here is an array containing the " { $link f } " class:"
220 { $example "{ POSTPONE: f } ." "{ POSTPONE: f }" }
221 "The " { $link f } " object is an instance of the " { $link f } " class:"
222 { $example "USE: classes" "f class ." "POSTPONE: f" }
223 "The " { $link f } " class is an instance of " { $link word } ":"
224 { $example "USE: classes" "\\ f class ." "word" }
225 "On the other hand, " { $link t } " is just a word, and there is no class which it is a unique instance of."
226 { $example "t \\ t eq? ." "t" }
227 "Many words which search collections confuse the case of no element being present with an element being found equal to " { $link f } ". If this distinction is imporant, there is usually an alternative word which can be used; for example, compare " { $link at } " with " { $link at* } "." ;
228
229 ARTICLE: "conditionals-boolean-equivalence" "Expressing conditionals with boolean logic"
230 "Certain simple conditional forms can be expressed in a simpler manner using boolean logic."
231 $nl
232 "The following two lines are equivalent:"
233 { $code "[ drop f ] unless" "swap and" }
234 "The following two lines are equivalent:"
235 { $code "[ ] [ ] ?if" "swap or" }
236 "The following two lines are equivalent, where " { $snippet "L" } " is a literal:"
237 { $code "[ L ] unless*" "L or" } ;
238
239 ARTICLE: "conditionals" "Conditional combinators"
240 "The basic conditionals:"
241 { $subsection if }
242 { $subsection when }
243 { $subsection unless }
244 "Forms abstracting a common stack shuffle pattern:"
245 { $subsection if* }
246 { $subsection when* }
247 { $subsection unless* }
248 "Another form abstracting a common stack shuffle pattern:"
249 { $subsection ?if }
250 "Sometimes instead of branching, you just need to pick one of two values:"
251 { $subsection ? }
252 "Two combinators which abstract out nested chains of " { $link if } ":"
253 { $subsection cond }
254 { $subsection case }
255 { $subsection "conditionals-boolean-equivalence" }
256 { $see-also "booleans" "bitwise-arithmetic" both? either? } ;
257
258 ARTICLE: "dataflow-combinators" "Data flow combinators"
259 "Data flow combinators pass values between quotations:"
260 { $subsection "slip-keep-combinators" }
261 { $subsection "cleave-combinators" }
262 { $subsection "spread-combinators" }
263 { $subsection "apply-combinators" }
264 { $see-also "curried-dataflow" } ;
265
266 ARTICLE: "combinators-quot" "Quotation construction utilities"
267 "Some words for creating quotations which can be useful for implementing method combinations and compiler transforms:"
268 { $subsection cond>quot }
269 { $subsection case>quot }
270 { $subsection alist>quot } ;
271
272 ARTICLE: "call" "Fundamental combinators"
273 "The most basic combinators are those that take either a quotation or word, and invoke it immediately. There are two sets of combinators; they differe in whether or not the stack effect of the expected code is declared."
274 $nl
275 "The simplest combinators do not take an effect declaration:"
276 { $subsection call }
277 { $subsection execute }
278 "These combinators only get optimized by the compiler if the quotation or word parameter is a literal; otherwise a compiler warning will result. Definitions of combinators which require literal parameters must be followed by the " { $link POSTPONE: inline } " declaration. For example:"
279 { $code
280     ": keep ( x quot -- x )"
281     "    over [ call ] dip ; inline"
282 }
283 "See " { $link "declarations" } " and " { $link "compiler-errors" } " for details."
284 $nl
285 "The other set of combinators allow arbitrary quotations and words to be called from optimized code. This is done by specifying the stack effect of the quotation literally. It is checked at runtime that the stack effect is accurate."
286 { $subsection call-effect }
287 { $subsection execute-effect }
288 "A simple layer of syntax sugar is defined on top:"
289 { $subsection POSTPONE: call( }
290 { $subsection POSTPONE: execute( }
291 "Unsafe calls declare an effect statically without any runtime checking:"
292 { $subsection call-effect-unsafe }
293 { $subsection execute-effect-unsafe }
294 { $see-also "effects" "inference" } ;
295
296 ARTICLE: "combinators" "Combinators"
297 "A central concept in Factor is that of a " { $emphasis "combinator" } ", which is a word taking code as input."
298 { $subsection "call" }
299 { $subsection "dataflow-combinators" }
300 { $subsection "conditionals" }
301 { $subsection "looping-combinators" }
302 { $subsection "compositional-combinators" }
303 { $subsection "combinators.short-circuit" }
304 { $subsection "combinators.smart" }
305 "More combinators are defined for working on data structures, such as " { $link "sequences-combinators" } " and " { $link "assocs-combinators" } "."
306 $nl
307 "The " { $vocab-link "combinators" } " provides some less frequently-used features."
308 $nl
309 "A combinator which can help with implementing methods on " { $link hashcode* } ":"
310 { $subsection recursive-hashcode }
311 { $subsection "combinators-quot" }
312 "Advanced topics:"
313 { $see-also "quotations" } ;
314
315 ABOUT: "combinators"
316
317 HELP: call-effect
318 { $values { "quot" quotation } { "effect" effect } }
319 { $description "Given a quotation and a stack effect, calls the quotation, asserting at runtime that it has the given stack effect. This is a macro which expands given a literal effect parameter, and an arbitrary quotation which is not required at compile time." } ;
320
321 HELP: execute-effect
322 { $values { "word" word } { "effect" effect } }
323 { $description "Given a word and a stack effect, executes the word, asserting at runtime that it has the given stack effect. This is a macro which expands given a literal effect parameter, and an arbitrary word which is not required at compile time." } ;
324
325 HELP: execute-effect-unsafe
326 { $values { "word" word } { "effect" effect } }
327 { $description "Given a word and a stack effect, executes the word, blindly declaring at runtime that it has the given stack effect. This is a macro which expands given a literal effect parameter, and an arbitrary word which is not required at compile time." }
328 { $warning "If the word being executed has an incorrect stack effect, undefined behavior will result. User code should use " { $link POSTPONE: execute( } " instead." } ;
329     
330 { call-effect call-effect-unsafe execute-effect execute-effect-unsafe } related-words
331
332 HELP: cleave
333 { $values { "x" object } { "seq" "a sequence of quotations with stack effect " { $snippet "( x -- ... )" } } }
334 { $description "Applies each quotation to the object in turn." }
335 { $examples
336     "The " { $link bi } " combinator takes one value and two quotations; the " { $link tri } " combinator takes one value and three quotations. The " { $link cleave } " combinator takes one value and any number of quotations, and is essentially equivalent to a chain of " { $link keep } " forms:"
337     { $code
338         "! Equivalent"
339         "{ [ p ] [ q ] [ r ] [ s ] } cleave"
340         "[ p ] keep [ q ] keep [ r ] keep s"
341     }
342 } ;
343
344 HELP: 2cleave
345 { $values { "x" object } { "y" object }
346           { "seq" "a sequence of quotations with stack effect " { $snippet "( x y -- ... )" } } }
347 { $description "Applies each quotation to the two objects in turn." } ;
348
349 HELP: 3cleave
350 { $values { "x" object } { "y" object } { "z" object }
351           { "seq" "a sequence of quotations with stack effect " { $snippet "( x y z -- ... )" } } }
352 { $description "Applies each quotation to the three objects in turn." } ;
353
354 { bi tri cleave } related-words
355
356 HELP: spread
357 { $values { "objs..." "objects" } { "seq" "a sequence of quotations with stack effect " { $snippet "( x -- ... )" } } }
358 { $description "Applies each quotation to the object in turn." }
359 { $examples
360     "The " { $link bi* } " combinator takes two values and two quotations; the " { $link tri* } " combinator takes three values and three quotations. The " { $link spread } " combinator takes " { $snippet "n" } " values and " { $snippet "n" } " quotations, where " { $snippet "n" } " is the length of the input sequence, and is essentially equivalent to series of retain stack manipulations:"
361     { $code
362         "! Equivalent"
363         "{ [ p ] [ q ] [ r ] [ s ] } spread"
364         "[ [ [ p ] dip q ] dip r ] dip s"
365     }
366 } ;
367
368 { bi* tri* spread } related-words
369
370 HELP: alist>quot
371 { $values { "default" "a quotation" } { "assoc" "a sequence of quotation pairs" } { "quot" "a new quotation" } }
372 { $description "Constructs a quotation which calls the first quotation in each pair of " { $snippet "assoc" } " until one of them outputs a true value, and then calls the second quotation in the corresponding pair. Quotations are called in reverse order, and if no quotation outputs a true value then " { $snippet "default" } " is called." }
373 { $notes "This word is used to implement compile-time behavior for " { $link cond } ", and it is also used by the generic word system. Note that unlike " { $link cond } ", the constructed quotation performs the tests starting from the end and not the beginning." } ;
374
375 HELP: cond
376 { $values { "assoc" "a sequence of quotation pairs and an optional quotation" } }
377 { $description
378     "Calls the second quotation in the first pair whose first quotation yields a true value. A single quotation will always yield a true value."
379     $nl
380     "The following two phrases are equivalent:"
381     { $code "{ { [ X ] [ Y ] } { [ Z ] [ T ] } } cond" }
382     { $code "X [ Y ] [ Z [ T ] [ no-cond ] if ] if" }
383 }
384 { $errors "Throws a " { $link no-cond } " error if none of the test quotations yield a true value." }
385 { $examples
386     { $code
387         "{"
388         "    { [ dup 0 > ] [ \"positive\" ] }"
389         "    { [ dup 0 < ] [ \"negative\" ] }"
390         "    [ \"zero\" ]"
391         "} cond"
392     }
393 } ;
394
395 HELP: no-cond
396 { $description "Throws a " { $link no-cond } " error." }
397 { $error-description "Thrown by " { $link cond } " if none of the test quotations yield a true value. Some uses of " { $link cond } " include a default case where the test quotation is " { $snippet "[ t ]" } "; such a " { $link cond } " form will never throw this error." } ;
398
399 HELP: case
400 { $values { "obj" object } { "assoc" "a sequence of object/word,quotation pairs, with an optional quotation at the end" } }
401 { $description
402     "Compares " { $snippet "obj" } " against the first element of every pair, first evaluating the first element if it is a word. If some pair matches, removes " { $snippet "obj" } " from the stack and calls the second element of that pair, which must be a quotation."
403     $nl
404     "If there is no case matching " { $snippet "obj" } ", the default case is taken. If the last element of " { $snippet "cases" } " is a quotation, the quotation is called with " { $snippet "obj" } " on the stack. Otherwise, a " { $link no-cond } " error is rasied."
405     $nl
406     "The following two phrases are equivalent:"
407     { $code "{ { X [ Y ] } { Z [ T ] } } case" }
408     { $code "dup X = [ drop Y ] [ dup Z = [ drop T ] [ no-case ] if ] if" }
409 }
410 { $examples
411     { $code
412         "SYMBOL: yes  SYMBOL: no  SYMBOL: maybe"
413         "maybe {"
414         "    { yes [ ] } ! Do nothing"
415         "    { no [ \"No way!\" throw ] }"
416         "    { maybe [ \"Make up your mind!\" print ] }"
417         "    [ \"Invalid input; try again.\" print ]"
418         "} case"
419     }
420 } ;
421
422 HELP: no-case
423 { $description "Throws a " { $link no-case } " error." }
424 { $error-description "Thrown by " { $link case } " if the object at the top of the stack does not match any case, and no default case is given." } ;
425
426 HELP: recursive-hashcode
427 { $values { "n" integer } { "obj" object } { "quot" { $quotation "( n obj -- code )" } } { "code" integer } }
428 { $description "A combinator used to implement methods for the " { $link hashcode* } " generic word. If " { $snippet "n" } " is less than or equal to zero, outputs 0, otherwise calls the quotation." } ;
429
430 HELP: cond>quot
431 { $values { "assoc" "a sequence of pairs of quotations" } { "quot" quotation } }
432 { $description  "Creates a quotation that when called, has the same effect as applying " { $link cond } " to " { $snippet "assoc" } "."
433 $nl
434 "the generated quotation is more efficient than the naive implementation of " { $link cond } ", though, since it expands into a series of conditionals, and no iteration through " { $snippet "assoc" } " has to be performed." }
435 { $notes "This word is used behind the scenes to compile " { $link cond } " forms efficiently; it can also be called directly,  which is useful for meta-programming." } ;
436
437 HELP: case>quot
438 { $values { "assoc" "a sequence of pairs of quotations" } { "default" quotation } { "quot" quotation } }
439 { $description "Creates a quotation that when called, has the same effect as applying " { $link case } " to " { $snippet "assoc" } "."
440 $nl
441 "This word uses three strategies:"
442 { $list
443     "If the assoc only has a few keys, a linear search is generated."
444     { "If the assoc has a large number of keys which form a contiguous range of integers, a direct dispatch is generated using the " { $link dispatch } " word together with a bounds check." }
445     "Otherwise, an open-coded hashtable dispatch is generated."
446 } } ;
447
448 HELP: distribute-buckets
449 { $values { "alist" "an alist" } { "initial" object } { "quot" { $quotation "( obj -- assoc )" } } { "buckets" "a new array" } }
450 { $description "Sorts the entries of " { $snippet "assoc" } " into buckets, using the quotation to yield a set of keys for each entry. The hashcode of each key is computed, and the entry is placed in all corresponding buckets. Each bucket is initially cloned from " { $snippet "initial" } "; this should either be an empty vector or a one-element vector containing a pair." }
451 { $notes "This word is used in the implemention of " { $link hash-case-quot } " and " { $link standard-combination } "." } ;
452
453 HELP: dispatch ( n array -- )
454 { $values { "n" "a fixnum" } { "array" "an array of quotations" } }
455 { $description "Calls the " { $snippet "n" } "th quotation in the array." }
456 { $warning "This word is in the " { $vocab-link "kernel.private" } " vocabulary because it is an implementation detail used by the generic word system to accelerate method dispatch. It does not perform type or bounds checks, and user code should not need to call it directly." } ;