]> gitweb.factorcode.org Git - factor.git/blob - core/kernel/kernel-docs.factor
Fix conflict
[factor.git] / core / kernel / kernel-docs.factor
1 USING: generic help.markup help.syntax math memory
2 namespaces sequences kernel.private layouts classes
3 kernel.private vectors combinators quotations strings words
4 assocs arrays math.order ;
5 IN: kernel
6
7 HELP: eq? ( obj1 obj2 -- ? )
8 { $values { "obj1" object } { "obj2" object } { "?" "a boolean" } }
9 { $description "Tests if two references point at the same object." } ;
10
11 HELP: drop  ( x -- )                 $shuffle ;
12 HELP: 2drop ( x y -- )               $shuffle ;
13 HELP: 3drop ( x y z -- )             $shuffle ;
14 HELP: dup   ( x -- x x )             $shuffle ;
15 HELP: 2dup  ( x y -- x y x y )       $shuffle ;
16 HELP: 3dup  ( x y z -- x y z x y z ) $shuffle ;
17 HELP: rot   ( x y z -- y z x )       $shuffle ;
18 HELP: -rot  ( x y z -- z x y )       $shuffle ;
19 HELP: dupd  ( x y -- x x y )         $shuffle ;
20 HELP: swapd ( x y z -- y x z )       $shuffle ;
21 HELP: nip   ( x y -- y )             $shuffle ;
22 HELP: 2nip  ( x y z -- z )           $shuffle ;
23 HELP: tuck  ( x y -- y x y )         $shuffle ;
24 HELP: over  ( x y -- x y x )         $shuffle ;
25 HELP: 2over                          $shuffle ;
26 HELP: pick  ( x y z -- x y z x )     $shuffle ;
27 HELP: swap  ( x y -- y x )           $shuffle ;
28 HELP: spin                           $shuffle ;
29 HELP: roll                           $shuffle ;
30 HELP: -roll                          $shuffle ;
31
32 HELP: datastack ( -- ds )
33 { $values { "ds" array } }
34 { $description "Outputs an array containing a copy of the data stack contents right before the call to this word, with the top of the stack at the end of the array." } ;
35
36 HELP: set-datastack ( ds -- )
37 { $values { "ds" array } }
38 { $description "Replaces the data stack contents with a copy of an array. The end of the array becomes the top of the stack." } ;
39
40 HELP: retainstack ( -- rs )
41 { $values { "rs" array } }
42 { $description "Outputs an array containing a copy of the retain stack contents right before the call to this word, with the top of the stack at the end of the array." } ;
43
44 HELP: set-retainstack ( rs -- )
45 { $values { "rs" array } }
46 { $description "Replaces the retain stack contents with a copy of an array. The end of the array becomes the top of the stack." } ;
47
48 HELP: callstack ( -- cs )
49 { $values { "cs" callstack } }
50 { $description "Outputs a copy of the call stack contents, with the top of the stack at the end of the vector. The stack frame of the caller word is " { $emphasis "not" } " included." } ;
51
52 HELP: set-callstack ( cs -- )
53 { $values { "cs" callstack } }
54 { $description "Replaces the call stack contents. The end of the vector becomes the top of the stack. Control flow is transferred immediately to the new call stack." } ;
55
56 HELP: clear
57 { $description "Clears the data stack." } ;
58
59 HELP: build
60 { $description "The current build number. Factor increments this number whenever a new boot image is created." } ;
61
62 HELP: hashcode*
63 { $values { "depth" integer } { "obj" object } { "code" fixnum } }
64 { $contract "Outputs the hashcode of an object. The hashcode operation must satisfy the following properties:"
65 { $list
66     { "If two objects are equal under " { $link = } ", they must have equal hashcodes." }
67     { "If the hashcode of an object depends on the values of its slots, the hashcode of the slots must be computed recursively by calling " { $link hashcode* } " with a " { $snippet "level" } " parameter decremented by one. This avoids excessive work while still computing well-distributed hashcodes. The " { $link recursive-hashcode } " combinator can help with implementing this logic," }
68     { "The hashcode should be a " { $link fixnum } ", however returning a " { $link bignum } " will not cause any problems other than potential performance degradation." }
69     { "The hashcode is only permitted to change between two invocations if the object or one of its slot values was mutated." }
70 }
71 "If mutable objects are used as hashtable keys, they must not be mutated in such a way that their hashcode changes. Doing so will violate bucket sorting invariants and result in undefined behavior. See " { $link "hashtables.keys" } " for details." } ;
72
73 HELP: hashcode
74 { $values { "obj" object } { "code" fixnum } }
75 { $description "Computes the hashcode of an object with a default hashing depth. See " { $link hashcode* } " for the hashcode contract." } ;
76
77 { hashcode hashcode* } related-words
78
79 HELP: =
80 { $values { "obj1" object } { "obj2" object } { "?" "a boolean" } }
81 { $description
82     "Tests if two objects are equal. If " { $snippet "obj1" } " and " { $snippet "obj2" } " point to the same object, outputs " { $link t } ". Otherwise, calls the " { $link equal? } " generic word."
83 }
84 { $examples
85     { $example "USING: kernel prettyprint ;" "5 5 = ." "t" }
86     { $example "USING: kernel prettyprint ;" "5 005 = ." "t" }
87     { $example "USING: kernel prettyprint ;" "5 5.0 = ." "f" }
88     { $example "USING: arrays kernel prettyprint ;" "{ \"a\" \"b\" } \"a\" \"b\" 2array = ." "t" }
89     { $example "USING: arrays kernel prettyprint ;" "{ \"a\" \"b\" } [ \"a\" \"b\" ] = ." "f" }
90 } ;
91
92 HELP: equal?
93 { $values { "obj1" object } { "obj2" object } { "?" "a boolean" } }
94 { $contract
95     "Tests if two objects are equal."
96     $nl
97     "User code should call " { $link = } " instead; that word first tests the case where the objects are " { $link eq? } ", and so by extension, methods defined on " { $link equal? } " assume they are never called on " { $link eq? } " objects."
98     $nl
99     "Method definitions should ensure that this is an equality relation, modulo the assumption that the two objects are not " { $link eq? } ". That is, for any three non-" { $link eq? } " objects " { $snippet "a" } ", " { $snippet "b" } " and " { $snippet "c" } ", we must have:"
100     { $list
101         { { $snippet "a = b" } " implies " { $snippet "b = a" } }
102         { { $snippet "a = b" } " and " { $snippet "b = c" } " implies " { $snippet "a = c" } }
103     }
104     "If a class defines a custom equality comparison test, it should also define a compatible method for the " { $link hashcode* } " generic word."
105 }
106 { $examples
107     "An example demonstrating why this word should only be used to define methods on, and never called directly:"
108     { $example "USING: kernel prettyprint ;" "5 5 equal? ." "f" }
109     "Using " { $link = } " gives the expected behavior:"
110     { $example "USING: kernel prettyprint ;" "5 5 = ." "t" }
111 } ;
112
113 HELP: identity-tuple
114 { $class-description "A class defining an " { $link equal? } " method which always returns f." }
115 { $examples
116     "To define a tuple class such that two instances are only equal if they are both the same instance, inherit from the " { $link identity-tuple } " class. This class defines a method on " { $link equal? } " which always returns " { $link f } ". Since " { $link = } " handles the case where the two objects are " { $link eq? } ", this method will never be called with two " { $link eq? } " objects, so such a definition is valid:"
117     { $code "TUPLE: foo < identity-tuple ;" }
118     "By calling " { $link = } " on instances of " { $snippet "foo" } " we get the results we expect:"
119     { $unchecked-example "T{ foo } dup = ." "t" }
120     { $unchecked-example "T{ foo } dup clone = ." "f" }
121 } ;
122
123 HELP: clone
124 { $values { "obj" object } { "cloned" "a new object" } }
125 { $contract "Outputs a new object equal to the given object. This is not guaranteed to actually copy the object; it does nothing with immutable objects, and does not copy words either. However, sequences and tuples can be cloned to obtain a shallow copy of the original." } ;
126
127 HELP: ?
128 { $values { "?" "a generalized boolean" } { "true" object } { "false" object } { "true/false" "one two input objects" } }
129 { $description "Chooses between two values depending on the boolean value of " { $snippet "cond" } "." } ;
130
131 HELP: >boolean
132 { $values { "obj" "a generalized boolean" } { "?" "a boolean" } }
133 { $description "Convert a generalized boolean into a boolean. That is, " { $link f } " retains its value, whereas anything else becomes " { $link t } "." } ;
134
135 HELP: not
136 { $values { "obj" "a generalized boolean" } { "?" "a boolean" } }
137 { $description "For " { $link f } " outputs " { $link t } " and for anything else outputs " { $link f } "." }
138 { $notes "This word implements boolean not, so applying it to integers will not yield useful results (all integers have a true value). Bitwise not is the " { $link bitnot } " word." } ;
139
140 HELP: and
141 { $values { "obj1" "a generalized boolean" } { "obj2" "a generalized boolean" } { "?" "a generalized boolean" } }
142 { $description "If both inputs are true, outputs " { $snippet "obj2" } ". otherwise outputs " { $link f } "." }
143 { $notes "This word implements boolean and, so applying it to integers will not yield useful results (all integers have a true value). Bitwise and is the " { $link bitand } " word." }
144 { $examples
145     "Usually only the boolean value of the result is used, however you can also explicitly rely on the behavior that if both inputs are true, the second is output:"
146     { $example "USING: kernel prettyprint ;" "t f and ." "f" }
147     { $example "USING: kernel prettyprint ;" "t 7 and ." "7" }
148     { $example "USING: kernel prettyprint ;" "\"hi\" 12.0 and ." "12.0" }
149 } ;
150
151 HELP: or
152 { $values { "obj1" "a generalized boolean" } { "obj2" "a generalized boolean" } { "?" "a generalized boolean" } }
153 { $description "If both inputs are false, outputs " { $link f } ". otherwise outputs the first of " { $snippet "obj1" } " and " { $snippet "obj2" } " which is true." }
154 { $notes "This word implements boolean inclusive or, so applying it to integers will not yield useful results (all integers have a true value). Bitwise inclusive or is the " { $link bitor } " word." }
155 { $examples
156     "Usually only the boolean value of the result is used, however you can also explicitly rely on the behavior that the result will be the first true input:"
157     { $example "USING: kernel prettyprint ;" "t f or ." "t" }
158     { $example "USING: kernel prettyprint ;" "\"hi\" 12.0 or ." "\"hi\"" }
159 } ;
160
161 HELP: xor
162 { $values { "obj1" "a generalized boolean" } { "obj2" "a generalized boolean" } { "?" "a generalized boolean" } }
163 { $description "If exactly one input is false, outputs the other input. Otherwise outputs " { $link f } "." }
164 { $notes "This word implements boolean exclusive or, so applying it to integers will not yield useful results (all integers have a true value). Bitwise exclusive or is the " { $link bitxor } " word." } ;
165
166 HELP: both?
167 { $values { "quot" { $quotation "( obj -- ? )" } } { "x" object } { "y" object } { "?" "a boolean" } }
168 { $description "Tests if the quotation yields a true value when applied to both " { $snippet "x" } " and " { $snippet "y" } "." }
169 { $examples
170     { $example "USING: kernel math prettyprint ;" "3 5 [ odd? ] both? ." "t" }
171     { $example "USING: kernel math prettyprint ;" "12 7 [ even? ] both? ." "f" }
172 } ;
173
174 HELP: either?
175 { $values { "quot" { $quotation "( obj -- ? )" } } { "x" object } { "y" object } { "?" "a boolean" } }
176 { $description "Tests if the quotation yields a true value when applied to either " { $snippet "x" } " or " { $snippet "y" } "." }
177 { $examples
178     { $example "USING: kernel math prettyprint ;" "3 6 [ odd? ] either? ." "t" }
179     { $example "USING: kernel math prettyprint ;" "5 7 [ even? ] either? ." "f" }
180 } ;
181
182 HELP: call
183 { $values { "callable" callable } }
184 { $description "Calls a quotation." }
185 { $examples
186     "The following two lines are equivalent:"
187     { $code "2 [ 2 + 3 * ] call" "2 2 + 3 *" }
188 } ;
189
190 HELP: call-clear ( quot -- )
191 { $values { "quot" callable } }
192 { $description "Calls a quotation with an empty call stack. If the quotation returns, Factor will exit.." }
193 { $notes "Used to implement " { $link "threads" } "." } ;
194
195 HELP: slip
196 { $values { "quot" quotation } { "x" object } }
197 { $description "Calls a quotation while hiding the top of the stack." } ;
198
199 HELP: 2slip
200 { $values { "quot" quotation } { "x" object } { "y" object } }
201 { $description "Calls a quotation while hiding the top two stack elements." } ;
202
203 HELP: 3slip
204 { $values { "quot" quotation } { "x" object } { "y" object } { "z" object } }
205 { $description "Calls a quotation while hiding the top three stack elements." } ;
206
207 HELP: keep
208 { $values { "quot" { $quotation "( x -- ... )" } } { "x" object } }
209 { $description "Call a quotation with a value on the stack, restoring the value when the quotation returns." }
210 { $examples
211     { $example "USING: arrays kernel prettyprint ;" "2 \"greetings\" [ <array> ] keep 2array ." "{ { \"greetings\" \"greetings\" } \"greetings\" }" }
212 } ;
213
214 HELP: 2keep
215 { $values { "quot" { $quotation "( x y -- ... )" } } { "x" object } { "y" object } }
216 { $description "Call a quotation with two values on the stack, restoring the values when the quotation returns." } ;
217
218 HELP: 3keep
219 { $values { "quot" { $quotation "( x y z -- ... )" } } { "x" object } { "y" object } { "z" object } }
220 { $description "Call a quotation with three values on the stack, restoring the values when the quotation returns." } ;
221
222 HELP: bi
223 { $values { "x" object } { "p" { $quotation "( x -- ... )" } } { "q" { $quotation "( x -- ... )" } } }
224 { $description "Applies " { $snippet "p" } " to " { $snippet "x" } ", then applies " { $snippet "q" } " to " { $snippet "x" } "." }
225 { $examples
226     "If " { $snippet "[ p ]" } " and " { $snippet "[ q ]" } " have stack effect " { $snippet "( x -- )" } ", then the following two lines are equivalent:"
227     { $code
228         "[ p ] [ q ] bi"
229         "dup p q"
230     }
231     "If " { $snippet "[ p ]" } " and " { $snippet "[ q ]" } " have stack effect " { $snippet "( x -- y )" } ", then the following two lines are equivalent:"
232     { $code
233         "[ p ] [ q ] bi"
234         "dup p swap q"
235     }
236     "In general, the following two lines are equivalent:"
237     { $code
238         "[ p ] [ q ] bi"
239         "[ p ] keep q"
240     }
241     
242 } ;
243
244 HELP: 2bi
245 { $values { "x" object } { "y" object } { "p" { $quotation "( x y -- ... )" } } { "q" { $quotation "( x y -- ... )" } } }
246 { $description "Applies " { $snippet "p" } " to the two input values, then applies " { $snippet "q" } " to the two input values." }
247 { $examples
248     "If " { $snippet "[ p ]" } " and " { $snippet "[ q ]" } " have stack effect " { $snippet "( x y -- )" } ", then the following two lines are equivalent:"
249     { $code
250         "[ p ] [ q ] 2bi"
251         "2dup p q"
252     }
253     "If " { $snippet "[ p ]" } " and " { $snippet "[ q ]" } " have stack effect " { $snippet "( x y -- z )" } ", then the following two lines are equivalent:"
254     { $code
255         "[ p ] [ q ] 2bi"
256         "2dup p -rot q"
257     }
258     "In general, the following two lines are equivalent:"
259     { $code
260         "[ p ] [ q ] 2bi"
261         "[ p ] 2keep q"
262     }
263 } ;
264
265 HELP: 3bi
266 { $values { "x" object } { "y" object } { "z" object } { "p" { $quotation "( x y z -- ... )" } } { "q" { $quotation "( x y z -- ... )" } } }
267 { $description "Applies " { $snippet "p" } " to the three input values, then applies " { $snippet "q" } " to the three input values." }
268 { $examples
269     "If " { $snippet "[ p ]" } " and " { $snippet "[ q ]" } " have stack effect " { $snippet "( x y z -- )" } ", then the following two lines are equivalent:"
270     { $code
271         "[ p ] [ q ] 3bi"
272         "3dup p q"
273     }
274     "If " { $snippet "[ p ]" } " and " { $snippet "[ q ]" } " have stack effect " { $snippet "( x y z -- w )" } ", then the following two lines are equivalent:"
275     { $code
276         "[ p ] [ q ] 3bi"
277         "3dup p -roll q"
278     }
279     "In general, the following two lines are equivalent:"
280     { $code
281         "[ p ] [ q ] 3bi"
282         "[ p ] 3keep q"
283     }
284 } ;
285
286 HELP: tri
287 { $values { "x" object } { "p" { $quotation "( x -- ... )" } } { "q" { $quotation "( x -- ... )" } } { "r" { $quotation "( x -- ... )" } } }
288 { $description "Applies " { $snippet "p" } " to " { $snippet "x" } ", then applies " { $snippet "q" } " to " { $snippet "x" } ", and finally applies " { $snippet "r" } " to " { $snippet "x" } "." }
289 { $examples
290     "If " { $snippet "[ p ]" } ", " { $snippet "[ q ]" } " and " { $snippet "[ r ]" } " have stack effect " { $snippet "( x -- )" } ", then the following two lines are equivalent:"
291     { $code
292         "[ p ] [ q ] [ r ] tri"
293         "dup p dup q r"
294     }
295     "If " { $snippet "[ p ]" } ", " { $snippet "[ q ]" } " and " { $snippet "[ r ]" } " have stack effect " { $snippet "( x -- y )" } ", then the following two lines are equivalent:"
296     { $code
297         "[ p ] [ q ] [ r ] tri"
298         "dup p over q rot r"
299     }
300     "In general, the following two lines are equivalent:"
301     { $code
302         "[ p ] [ q ] [ r ] tri"
303         "[ p ] keep [ q ] keep r"
304     }
305 } ;
306
307 HELP: 2tri
308 { $values { "x" object } { "y" object } { "p" { $quotation "( x y -- ... )" } } { "q" { $quotation "( x y -- ... )" } } { "r" { $quotation "( x y -- ... )" } } }
309 { $description "Applies " { $snippet "p" } " to the two input values, then applies " { $snippet "q" } " to the two input values, and finally applies " { $snippet "r" } " to the two input values." }
310 { $examples
311     "If " { $snippet "[ p ]" } ", " { $snippet "[ q ]" } " and " { $snippet "[ r ]" } " have stack effect " { $snippet "( x y -- )" } ", then the following two lines are equivalent:"
312     { $code
313         "[ p ] [ q ] [ r ] 2tri"
314         "2dup p 2dup q r"
315     }
316     "In general, the following two lines are equivalent:"
317     { $code
318         "[ p ] [ q ] [ r ] 2tri"
319         "[ p ] 2keep [ q ] 2keep r"
320     }
321 } ;
322
323 HELP: 3tri
324 { $values { "x" object } { "y" object } { "z" object } { "p" { $quotation "( x y z -- ... )" } } { "q" { $quotation "( x y z -- ... )" } } { "r" { $quotation "( x y z -- ... )" } } }
325 { $description "Applies " { $snippet "p" } " to the three input values, then applies " { $snippet "q" } " to the three input values, and finally applies " { $snippet "r" } " to the three input values." }
326 { $examples
327     "If " { $snippet "[ p ]" } ", " { $snippet "[ q ]" } " and " { $snippet "[ r ]" } " have stack effect " { $snippet "( x y z -- )" } ", then the following two lines are equivalent:"
328     { $code
329         "[ p ] [ q ] [ r ] 3tri"
330         "3dup p 3dup q r"
331     }
332     "In general, the following two lines are equivalent:"
333     { $code
334         "[ p ] [ q ] [ r ] 3tri"
335         "[ p ] 3keep [ q ] 3keep r"
336     }
337 } ;
338
339
340 HELP: bi*
341 { $values { "x" object } { "y" object } { "p" { $quotation "( x -- ... )" } } { "q" { $quotation "( y -- ... )" } } }
342 { $description "Applies " { $snippet "p" } " to " { $snippet "x" } ", then applies " { $snippet "q" } " to " { $snippet "y" } "." }
343 { $examples
344     "The following two lines are equivalent:"
345     { $code
346         "[ p ] [ q ] bi*"
347         "[ p ] dip q"
348     }
349 } ;
350
351 HELP: 2bi*
352 { $values { "w" object } { "x" object } { "y" object } { "z" object } { "p" { $quotation "( w x -- ... )" } } { "q" { $quotation "( y z -- ... )" } } }
353 { $description "Applies " { $snippet "p" } " to " { $snippet "w" } " and " { $snippet "x" } ", then applies " { $snippet "q" } " to " { $snippet "y" } " and " { $snippet "z" } "." }
354 { $examples
355     "The following two lines are equivalent:"
356     { $code
357         "[ p ] [ q ] 2bi*"
358         "[ p ] 2dip q"
359     }
360 } ;
361
362 HELP: 2tri*
363 { $values { "u" object } { "v" object } { "w" object } { "x" object } { "y" object } { "z" object } { "p" { $quotation "( u v -- ... )" } } { "q" { $quotation "( w x -- ... )" } } { "r" { $quotation "( y z -- ... )" } } }
364 { $description "Applies " { $snippet "p" } " to " { $snippet "u" } " and " { $snippet "v" } ", then applies " { $snippet "q" } " to " { $snippet "w" } " and " { $snippet "x" } ", and finally applies " { $snippet "r" } " to " { $snippet "y" } " and " { $snippet "z" } "." }
365 { $examples
366     "The following two lines are equivalent:"
367     { $code
368         "[ p ] [ q ] [ r ] 2tri*"
369         "[ [ p ] 2dip q ] 2dip r"
370     }
371 } ;
372
373 HELP: tri*
374 { $values { "x" object } { "y" object } { "z" object } { "p" { $quotation "( x -- ... )" } } { "q" { $quotation "( y -- ... )" } } { "r" { $quotation "( z -- ... )" } } }
375 { $description "Applies " { $snippet "p" } " to " { $snippet "x" } ", then applies " { $snippet "q" } " to " { $snippet "y" } ", and finally applies " { $snippet "r" } " to " { $snippet "z" } "." }
376 { $examples
377     "The following two lines are equivalent:"
378     { $code
379         "[ p ] [ q ] [ r ] tri*"
380         "[ [ p ] dip q ] dip r"
381     }
382 } ;
383
384 HELP: bi@
385 { $values { "x" object } { "y" object } { "quot" { $quotation "( obj -- ... )" } } }
386 { $description "Applies the quotation to " { $snippet "x" } ", then to " { $snippet "y" } "." }
387 { $examples
388     "The following two lines are equivalent:"
389     { $code
390         "[ p ] bi@"
391         "[ p ] dip p"
392     }
393     "The following two lines are also equivalent:"
394     { $code
395         "[ p ] bi@"
396         "[ p ] [ p ] bi*"
397     }
398 } ;
399
400 HELP: 2bi@
401 { $values { "w" object } { "x" object } { "y" object } { "z" object } { "quot" { $quotation "( obj1 obj2 -- ... )" } } }
402 { $description "Applies the quotation to " { $snippet "w" } " and " { $snippet "x" } ", then to " { $snippet "y" } " and " { $snippet "z" } "." }
403 { $examples
404     "The following two lines are equivalent:"
405     { $code
406         "[ p ] 2bi@"
407         "[ p ] 2dip p"
408     }
409     "The following two lines are also equivalent:"
410     { $code
411         "[ p ] 2bi@"
412         "[ p ] [ p ] 2bi*"
413     }
414 } ;
415
416 HELP: tri@
417 { $values { "x" object } { "y" object } { "z" object } { "quot" { $quotation "( obj -- ... )" } } }
418 { $description "Applies the quotation to " { $snippet "x" } ", then to " { $snippet "y" } ", and finally to " { $snippet "z" } "." }
419 { $examples
420     "The following two lines are equivalent:"
421     { $code
422         "[ p ] tri@"
423         "[ [ p ] dip p ] dip p"
424     }
425     "The following two lines are also equivalent:"
426     { $code
427         "[ p ] tri@"
428         "[ p ] [ p ] [ p ] tri*"
429     }
430 } ;
431
432 HELP: 2tri@
433 { $values { "u" object } { "v" object } { "w" object } { "x" object } { "y" object } { "z" object } { "quot" { $quotation "( obj1 obj2 -- ... )" } } }
434 { $description "Applies the quotation to " { $snippet "u" } " and " { $snippet "v" } ", then to " { $snippet "w" } " and " { $snippet "x" } ", and then to " { $snippet "y" } " and " { $snippet "z" } "." }
435 { $examples
436     "The following two lines are equivalent:"
437     { $code
438         "[ p ] 2tri@"
439         "[ [ p ] 2dip p ] 2dip p"
440     }
441     "The following two lines are also equivalent:"
442     { $code
443         "[ p ] 2tri@"
444         "[ p ] [ p ] [ p ] 2tri*"
445     }
446 } ;
447
448 HELP: bi-curry
449 { $values { "x" object } { "p" { $quotation "( x -- ... )" } } { "q" { $quotation "( x -- ... )" } } { "p'" { $snippet "[ x p ]" } } { "q'" { $snippet "[ x q ]" } } }
450 { $description "Partially applies " { $snippet "p" } " and " { $snippet "q" } " to " { $snippet "x" } "." }
451 { $notes
452   "The following two lines are equivalent:"
453   { $code
454     "[ p ] [ q ] bi-curry [ call ] bi@"
455     "[ p ] [ q ] bi"
456   }
457   "Higher-arity variants of " { $link bi } " can be built from " { $link bi-curry } ":"
458   { $code
459     "[ p ] [ q ] bi-curry bi == [ p ] [ q ] 2bi"
460     "[ p ] [ q ] bi-curry bi-curry bi == [ p ] [ q ] 3bi"
461   }
462   "The combination " { $snippet "bi-curry bi*" } " cannot be expressed with the non-currying dataflow combinators alone; it is equivalent to a stack shuffle preceding " { $link 2bi* } ":"
463   { $code
464     "[ p ] [ q ] bi-curry bi*"
465     "[ swap ] keep [ p ] [ q ] 2bi*"
466   }
467   "To put it another way, " { $snippet "bi-curry bi*" } " handles the case where you have three values " { $snippet "a b c" } " on the stack, and you wish to apply " { $snippet "p" } " to " { $snippet "a c" } " and " { $snippet "q" } " to " { $snippet "b c" } "."
468 } ;
469
470 HELP: tri-curry
471 { $values
472   { "x" object }
473   { "p" { $quotation "( x -- ... )" } }
474   { "q" { $quotation "( x -- ... )" } }
475   { "r" { $quotation "( x -- ... )" } }
476   { "p'" { $snippet "[ x p ]" } }
477   { "q'" { $snippet "[ x q ]" } }
478   { "r'" { $snippet "[ x r ]" } }
479 }
480 { $description "Partially applies " { $snippet "p" } ", " { $snippet "q" } " and " { $snippet "r" } " to " { $snippet "x" } "." }
481 { $notes
482   "The following two lines are equivalent:"
483   { $code
484     "[ p ] [ q ] [ r ] tri-curry [ call ] tri@"
485     "[ p ] [ q ] [ r ] tri"
486   }
487   "Higher-arity variants of " { $link tri } " can be built from " { $link tri-curry } ":"
488   { $code
489     "[ p ] [ q ] [ r ] tri-curry tri == [ p ] [ q ] [ r ] 2tri"
490     "[ p ] [ q ] [ r ] tri-curry tri-curry bi == [ p ] [ q ] [ r ] 3tri"
491   }
492   "The combination " { $snippet "tri-curry tri*" } " cannot be expressed with the non-currying dataflow combinators alone; it handles the case where you have four values " { $snippet "a b c d" } " on the stack, and you wish to apply " { $snippet "p" } " to " { $snippet "a d" } ", " { $snippet "q" } " to " { $snippet "b d" } " and " { $snippet "r" } " to " { $snippet "c d" } "." } ;
493
494 HELP: bi-curry*
495 { $values { "x" object } { "y" object } { "p" { $quotation "( x -- ... )" } } { "q" { $quotation "( y -- ... )" } } { "p'" { $snippet "[ x p ]" } } { "q'" { $snippet "[ y q ]" } } }
496 { $description "Partially applies " { $snippet "p" } " to " { $snippet "x" } ", and " { $snippet "q" } " to " { $snippet "y" } "." }
497 { $notes
498   "The following two lines are equivalent:"
499   { $code
500     "[ p ] [ q ] bi-curry* [ call ] bi@"
501     "[ p ] [ q ] bi*"
502   }
503   "The combination " { $snippet "bi-curry* bi" } " is equivalent to a stack shuffle preceding " { $link 2bi* } ":"
504   { $code
505     "[ p ] [ q ] bi-curry* bi"
506     "[ over ] dip [ p ] [ q ] 2bi*"
507   }
508   "In other words, " { $snippet "bi-curry* bi" } " handles the case where you have the three values " { $snippet "a b c" } " on the stack, and you wish to apply " { $snippet "p" } " to " { $snippet "a b" } " and " { $snippet "q" } " to " { $snippet "a c" } "."
509   $nl
510   "The combination " { $snippet "bi-curry* bi*" } " is equivalent to a stack shuffle preceding " { $link 2bi* } ":"
511   { $code
512     "[ p ] [ q ] bi-curry* bi*"
513     "[ swap ] dip [ p ] [ q ] 2bi*"
514   }
515   "In other words, " { $snippet "bi-curry* bi*" } " handles the case where you have the four values " { $snippet "a b c d" } " on the stack, and you wish to apply " { $snippet "p" } " to " { $snippet "a c" } " and " { $snippet "q" } " to " { $snippet "b d" } "."
516   
517 } ;
518
519 HELP: tri-curry*
520 { $values
521   { "x" object }
522   { "y" object }
523   { "z" object }
524   { "p" { $quotation "( x -- ... )" } }
525   { "q" { $quotation "( y -- ... )" } }
526   { "r" { $quotation "( z -- ... )" } }
527   { "p'" { $snippet "[ x p ]" } }
528   { "q'" { $snippet "[ y q ]" } }
529   { "r'" { $snippet "[ z r ]" } }
530 }
531 { $description "Partially applies " { $snippet "p" } " to " { $snippet "x" } ", " { $snippet "q" } " to " { $snippet "y" } " and " { $snippet "r" } " to " { $snippet "z" } "." }
532 { $notes
533   "The following two lines are equivalent:"
534   { $code
535     "[ p ] [ q ] [ r ] tri-curry* [ call ] tri@"
536     "[ p ] [ q ] [ r ] tri*"
537   }
538   "The combination " { $snippet "tri-curry* tri" } " is equivalent to a stack shuffle preceding " { $link 2tri* } ":"
539   { $code
540     "[ p ] [ q ] [ r ] tri-curry* tri"
541     "[ [ over ] dip over ] dip [ p ] [ q ] [ r ] 2tri*"
542   }
543 } ;
544
545 HELP: bi-curry@
546 { $values { "x" object } { "y" object } { "q" { $quotation "( obj -- ... )" } } { "p'" { $snippet "[ x q ]" } } { "q'" { $snippet "[ y q ]" } } }
547 { $description "Partially applies " { $snippet "q" } " to " { $snippet "x" } " and " { $snippet "y" } "." }
548 { $notes
549   "The following two lines are equivalent:"
550   { $code
551     "[ q ] bi-curry@"
552     "[ q ] [ q ] bi-curry*"
553   }
554 } ;
555
556 HELP: tri-curry@
557 { $values
558   { "x" object }
559   { "y" object }
560   { "z" object }
561   { "q" { $quotation "( obj -- ... )" } }
562   { "p'" { $snippet "[ x q ]" } }
563   { "q'" { $snippet "[ y q ]" } }
564   { "r'" { $snippet "[ z q ]" } }
565 }
566 { $description "Partially applies " { $snippet "q" } " to " { $snippet "x" } ", " { $snippet "y" } " and " { $snippet "z" } "." }
567 { $notes
568   "The following two lines are equivalent:"
569   { $code
570     "[ q ] tri-curry@"
571     "[ q ] [ q ] [ q ] tri-curry*"
572   }
573 } ;
574
575 HELP: if
576 { $values { "?" "a generalized boolean" } { "true" quotation } { "false" quotation } }
577 { $description "If " { $snippet "cond" } " is " { $link f } ", calls the " { $snippet "false" } " quotation. Otherwise calls the " { $snippet "true" } " quotation."
578 $nl
579 "The " { $snippet "cond" } " value is removed from the stack before either quotation is called." } ;
580
581 HELP: when
582 { $values { "?" "a generalized boolean" } { "true" quotation } }
583 { $description "If " { $snippet "cond" } " is not " { $link f } ", calls the " { $snippet "true" } " quotation."
584 $nl
585 "The " { $snippet "cond" } " value is removed from the stack before the quotation is called." } ;
586
587 HELP: unless
588 { $values { "?" "a generalized boolean" } { "false" quotation } }
589 { $description "If " { $snippet "cond" } " is " { $link f } ", calls the " { $snippet "false" } " quotation."
590 $nl
591 "The " { $snippet "cond" } " value is removed from the stack before the quotation is called." } ;
592
593 HELP: if*
594 { $values { "?" "a generalized boolean" } { "true" { $quotation "( cond -- ... )" } } { "false" quotation } }
595 { $description "Alternative conditional form that preserves the " { $snippet "cond" } " value if it is true."
596 $nl
597 "If the condition is true, it is retained on the stack before the " { $snippet "true" } " quotation is called. Otherwise, the condition is removed from the stack and the " { $snippet "false" } " quotation is called."
598 $nl
599 "The following two lines are equivalent:"
600 { $code "X [ Y ] [ Z ] if*" "X dup [ Y ] [ drop Z ] if" } } ;
601
602 HELP: when*
603 { $values { "?" "a generalized boolean" } { "true" { $quotation "( cond -- ... )" } } }
604 { $description "Variant of " { $link if* } " with no false quotation."
605 $nl
606 "The following two lines are equivalent:"
607 { $code "X [ Y ] when*" "X dup [ Y ] [ drop ] if" } } ;
608
609 HELP: unless*
610 { $values { "?" "a generalized boolean" } { "false" "a quotation " } }
611 { $description "Variant of " { $link if* } " with no true quotation." }
612 { $notes
613 "The following two lines are equivalent:"
614 { $code "X [ Y ] unless*" "X dup [ ] [ drop Y ] if" } } ;
615
616 HELP: ?if
617 { $values { "default" object } { "cond" "a generalized boolean" } { "true" { $quotation "( cond -- ... )" } } { "false" { $quotation "( default -- ... )" } } }
618 { $description "If the condition is " { $link f } ", the " { $snippet "false" } " quotation is called with the " { $snippet "default" } " value on the stack. Otherwise, the " { $snippet "true" } " quotation is called with the condition on the stack." }
619 { $notes
620 "The following two lines are equivalent:"
621 { $code "[ X ] [ Y ] ?if" "dup [ nip X ] [ drop Y ] if" }
622 "The following two lines are equivalent:"
623 { $code "[ ] [ ] ?if" "swap or" } } ;
624
625 HELP: die
626 { $description "Starts the front-end processor (FEP), which is a low-level debugger which can inspect memory addresses and the like. The FEP is also entered when a critical error occurs." }
627 { $notes
628     "The term FEP originates from the Lisp machines of old. According to the Jargon File,"
629     $nl
630     { $strong "fepped out" } " /fept owt/ " { $emphasis "adj." }  " The Symbolics 3600 LISP Machine has a Front-End Processor called a `FEP' (compare sense 2 of box). When the main processor gets wedged, the FEP takes control of the keyboard and screen. Such a machine is said to have `fepped out' or `dropped into the fep'." 
631     $nl
632     { $url "http://www.jargon.net/jargonfile/f/feppedout.html" }
633 } ;
634
635 HELP: (clone) ( obj -- newobj )
636 { $values { "obj" object } { "newobj" "a shallow copy" } }
637 { $description "Outputs a byte-by-byte copy of the given object. User code should call " { $link clone } " instead." } ;
638
639 HELP: declare
640 { $values { "spec" "an array of class words" } }
641 { $description "Declares that the elements at the top of the stack are instances of the classes in " { $snippet "spec" } "." }
642 { $warning "The compiler blindly trusts declarations, and false declarations can lead to crashes, memory corruption and other undesirable behavior." }
643 { $examples
644     "The optimizer cannot do anything with the below code:"
645     { $code "2 + 10 *" }
646     "However, if we declare that the top of the stack is a " { $link float } ", then type checks and generic dispatch are eliminated, and the compiler can use unsafe intrinsics:"
647     { $code "{ float } declare 2 + 10 *" }
648 } ;
649
650 HELP: tag ( object -- n )
651 { $values { "object" object } { "n" "a tag number" } }
652 { $description "Outputs an object's tag number, between zero and one less than " { $link num-tags } ". This is implementation detail and user code should call " { $link class } " instead." } ;
653
654 HELP: getenv ( n -- obj )
655 { $values { "n" "a non-negative integer" } { "obj" object } }
656 { $description "Reads an object from the Factor VM's environment table. User code never has to read the environment table directly; instead, use one of the callers of this word." } ;
657
658 HELP: setenv ( obj n -- )
659 { $values { "n" "a non-negative integer" } { "obj" object } }
660 { $description "Writes an object to the Factor VM's environment table. User code never has to write to the environment table directly; instead, use one of the callers of this word." } ;
661
662 HELP: object
663 { $class-description
664     "The class of all objects. If a generic word defines a method specializing on this class, the method is used as a fallback, if no other applicable method is found. For instance:"
665     { $code "GENERIC: enclose" "M: number enclose 1array ;" "M: object enclose ;" }
666 } ;
667
668 HELP: null
669 { $class-description
670     "The canonical empty class with no instances."
671 } ;
672
673 HELP: most
674 { $values { "x" object } { "y" object } { "quot" { $quotation "( x y -- ? )" } } { "z" "either " { $snippet "x" } " or " { $snippet "y" } } }
675 { $description "If the quotation yields a true value when applied to " { $snippet "x" } " and " { $snippet "y" } ", outputs " { $snippet "x" } ", otherwise outputs " { $snippet "y" } "." } ;
676
677 HELP: curry
678 { $values { "obj" object } { "quot" callable } { "curry" curry } }
679 { $description "Partial application. Outputs a " { $link callable } " which first pushes " { $snippet "obj" } " and then calls " { $snippet "quot" } "." }
680 { $class-description "The class of objects created by " { $link curry } ". These objects print identically to quotations and implement the sequence protocol, however they only use two cells of storage; a reference to the object and a reference to the underlying quotation." }
681 { $notes "Even if " { $snippet "obj" } " is a word, it will be pushed as a literal."
682 $nl
683 "This operation is efficient and does not copy the quotation." }
684 { $examples
685     { $example "USING: kernel prettyprint ;" "5 [ . ] curry ." "[ 5 . ]" }
686     { $example "USING: kernel prettyprint ;" "\\ = [ see ] curry ." "[ \\ = see ]" }
687     { $example "USING: kernel math prettyprint sequences ;" "{ 1 2 3 } 2 [ - ] curry map ." "{ -1 0 1 }" }
688 } ;
689
690 HELP: 2curry
691 { $values { "obj1" object } { "obj2" object } { "quot" callable } { "curry" curry } }
692 { $description "Outputs a " { $link callable } " which pushes " { $snippet "obj1" } " and " { $snippet "obj2" } " and then calls " { $snippet "quot" } "." }
693 { $notes "This operation is efficient and does not copy the quotation." }
694 { $examples
695     { $example "USING: kernel math prettyprint ;" "5 4 [ + ] 2curry ." "[ 5 4 + ]" }
696 } ;
697
698 HELP: 3curry
699 { $values { "obj1" object } { "obj2" object } { "obj3" object } { "quot" callable } { "curry" curry } }
700 { $description "Outputs a " { $link callable } " which pushes " { $snippet "obj1" } ", " { $snippet "obj2" } " and " { $snippet "obj3" } ", and then calls " { $snippet "quot" } "." }
701 { $notes "This operation is efficient and does not copy the quotation." } ;
702
703 HELP: with
704 { $values { "param" object } { "obj" object } { "quot" { $quotation "( param elt -- ... )" } } { "obj" object } { "curry" curry } }
705 { $description "Partial application on the left. The following two lines are equivalent:"
706     { $code "swap [ swap A ] curry B" }
707     { $code "[ A ] with B" }
708     
709 }
710 { $notes "This operation is efficient and does not copy the quotation." }
711 { $examples
712     { $example "USING: kernel math prettyprint sequences ;" "2 { 1 2 3 } [ - ] with map ." "{ 1 0 -1 }" }
713 } ;
714
715 HELP: compose
716 { $values { "quot1" callable } { "quot2" callable } { "compose" compose } }
717 { $description "Quotation composition. Outputs a " { $link callable } " which calls " { $snippet "quot1" } " followed by " { $snippet "quot2" } "." }
718 { $notes
719     "The following two lines are equivalent:"
720     { $code
721         "compose call"
722         "append call"
723     }
724     "However, " { $link compose } " runs in constant time, and the optimizing compiler is able to compile code which calls composed quotations."
725 } ;
726
727
728 HELP: prepose
729 { $values { "quot1" callable } { "quot2" callable } { "compose" compose } }
730 { $description "Quotation composition. Outputs a " { $link callable } " which calls " { $snippet "quot2" } " followed by " { $snippet "quot1" } "." }
731 { $notes "See " { $link compose } " for details." } ;
732
733 { compose prepose } related-words
734
735 HELP: dip
736 { $values { "x" object } { "quot" quotation } }
737 { $description "Calls " { $snippet "quot" } " with " { $snippet "obj" } " hidden on the retain stack." }
738 { $examples
739     { $example "USING: arrays kernel math prettyprint ;" "10 20 30 [ / ] dip 2array ." "{ 1/2 30 }" }
740 } ;
741
742 HELP: 2dip
743 { $values { "x" object } { "y" object } { "quot" quotation } }
744 { $description "Calls " { $snippet "quot" } " with " { $snippet "x" } " and " { $snippet "y" } " hidden on the retain stack." }
745 { $notes "The following are equivalent:"
746     { $code "[ [ foo bar ] dip ] dip" }
747     { $code "[ foo bar ] 2dip" }
748 } ;
749
750 HELP: 3dip
751 { $values { "x" object } { "y" object } { "z" object } { "quot" quotation } }
752 { $description "Calls " { $snippet "quot" } " with " { $snippet "x" } ", " { $snippet "y" } " and " { $snippet "z" } " hidden on the retain stack." }
753 { $notes "The following are equivalent:"
754     { $code "[ [ [ foo bar ] dip ] dip ] dip" }
755     { $code "[ foo bar ] 3dip" }
756 } ;
757
758 HELP: 4dip
759 { $values { "w" object } { "x" object } { "y" object } { "z" object } { "quot" quotation } }
760 { $description "Calls " { $snippet "quot" } " with " { $snippet "w" } ", " { $snippet "x" } ", " { $snippet "y" } " and " { $snippet "z" } " hidden on the retain stack." }
761 { $notes "The following are equivalent:"
762     { $code "[ [ [ [ foo bar ] dip ] dip ] dip ] dip" }
763     { $code "[ foo bar ] 4dip" }
764 } ;
765
766 HELP: while
767 { $values { "pred" { $quotation "( -- ? )" } } { "body" "a quotation" } { "tail" "a quotation" } }
768 { $description "Calls " { $snippet "body" } " until " { $snippet "pred" } " returns " { $link f } "." } ;
769
770 HELP: until
771 { $values { "pred" { $quotation "( -- ? )" } } { "body" "a quotation" } { "tail" "a quotation" } }
772 { $description "Calls " { $snippet "body" } " until " { $snippet "pred" } " returns " { $link t } "." } ;
773
774 HELP: do
775 { $values { "pred" { $quotation "( -- ? )" } } { "body" "a quotation" } { "tail" "a quotation" } }
776 { $description "Executes one iteration of a " { $link while } " or " { $link until } " loop." } ;
777
778 HELP: loop
779 { $values
780      { "pred" quotation } }
781      { $description "Calls the quotation repeatedly until it outputs " { $link f } "." }
782 { $examples "Loop until we hit a zero:"
783     { $unchecked-example "USING: kernel random math io ; "
784     " [ \"hi\" write bl 10 random zero? not ] loop"
785     "hi hi hi" }
786     "A fun loop:"
787     { $example "USING: kernel prettyprint math ; "
788     "3 [ dup . 7 + 11 mod dup 3 = not ] loop drop"
789     "3\n10\n6\n2\n9\n5\n1\n8\n4\n0\n7" }
790 } ;
791
792 ARTICLE: "looping-combinators" "Looping combinators"
793 "In most cases, loops should be written using high-level combinators (such as " { $link "sequences-combinators" } ") or tail recursion. However, sometimes, the best way to express intent is with a loop."
794 { $subsection while }
795 { $subsection until }
796 "The above two combinators take a " { $snippet "tail" } " quotation. Strictly speaking, the " { $snippet "tail" } " is not necessary, since the following are equivalent:"
797 { $code
798     "[ P ] [ Q ] [ T ] while"
799     "[ P ] [ Q ] [ ] while T"
800 }
801 "However, depending on the stack effects of " { $snippet "pred" } " and " { $snippet "quot" } ", the " { $snippet "tail" } " quotation might need to be non-empty in order to balance out the stack effect of branches for stack effect inference."
802 $nl
803 "To execute one iteration of a loop, use the following word:"
804 { $subsection do }
805 "This word is intended as a modifier. The normal " { $link while } " loop never executes the body if the predicate returns first on the first iteration. To ensure the body executes at least once, use " { $link do } ":"
806 { $code
807     "[ P ] [ Q ] [ T ] do while"
808 }
809 "A simpler looping combinator which executes a single quotation until it returns " { $link f } ":"
810 { $subsection loop } ;
811
812 HELP: assert
813 { $values { "got" "the obtained value" } { "expect" "the expected value" } }
814 { $description "Throws an " { $link assert } " error." }
815 { $error-description "Thrown when a unit test or other assertion fails." } ;
816
817 HELP: assert=
818 { $values { "a" object } { "b" object } }
819 { $description "Throws an " { $link assert } " error if " { $snippet "a" } " does not equal " { $snippet "b" } "." } ;
820
821 ARTICLE: "shuffle-words" "Shuffle words"
822 "Shuffle words rearrange items at the top of the data stack. They control the flow of data between words that perform actions."
823 $nl
824 "The " { $link "cleave-combinators" } ", " { $link "spread-combinators" } " and " { $link "apply-combinators" } " are closely related to shuffle words and should be used instead where possible because they can result in clearer code; also, see the advice in " { $link "cookbook-philosophy" } "."
825 $nl
826 "Removing stack elements:"
827 { $subsection drop }
828 { $subsection 2drop }
829 { $subsection 3drop }
830 { $subsection nip }
831 { $subsection 2nip }
832 "Duplicating stack elements:"
833 { $subsection dup }
834 { $subsection 2dup }
835 { $subsection 3dup }
836 { $subsection dupd }
837 { $subsection over }
838 { $subsection 2over }
839 { $subsection pick }
840 { $subsection tuck }
841 "Permuting stack elements:"
842 { $subsection swap }
843 { $subsection swapd }
844 { $subsection rot }
845 { $subsection -rot }
846 { $subsection spin }
847 { $subsection roll }
848 { $subsection -roll } ;
849
850 ARTICLE: "cleave-shuffle-equivalence" "Expressing shuffle words with cleave combinators"
851 "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 } "."
852 $nl
853 "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:"
854 { $code
855     ": keep  [ ] bi ;"
856     ": 2keep [ ] 2bi ;"
857     ": 3keep [ ] 3bi ;"
858     ""
859     ": dup   [ ] [ ] bi ;"
860     ": 2dup  [ ] [ ] 2bi ;"
861     ": 3dup  [ ] [ ] 3bi ;"
862     ""
863     ": tuck  [ nip ] [ ] 2bi ;"
864     ": swap  [ nip ] [ drop ] 2bi ;"
865     ""
866     ": over  [ ] [ drop ] 2bi ;"
867     ": pick  [ ] [ 2drop ] 3bi ;"
868     ": 2over [ ] [ drop ] 3bi ;"
869 } ;
870
871 ARTICLE: "cleave-combinators" "Cleave combinators"
872 "The cleave combinators apply multiple quotations to a single value."
873 $nl
874 "Two quotations:"
875 { $subsection bi }
876 { $subsection 2bi }
877 { $subsection 3bi }
878 "Three quotations:"
879 { $subsection tri }
880 { $subsection 2tri }
881 { $subsection 3tri }
882 "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:"
883 { $code
884     "! First alternative; uses keep"
885     "[ 1 + ] keep"
886     "[ 1 - ] keep"
887     "2 *"
888     "! Second alternative: uses tri"
889     "[ 1 + ]"
890     "[ 1 - ]"
891     "[ 2 * ] tri"
892 }
893 "The latter is more aesthetically pleasing than the former."
894 $nl
895 "A generalization of the above combinators to any number of quotations can be found in " { $link "combinators" } "."
896 { $subsection "cleave-shuffle-equivalence" } ;
897
898 ARTICLE: "spread-shuffle-equivalence" "Expressing shuffle words with spread combinators"
899 "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* } "."
900 $nl
901 "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:"
902 { $code
903     ": dip   [ ] bi* ;"
904     ": 2dip  [ ] [ ] tri* ;"
905     ""
906     ": slip  [ call ] [ ] bi* ;"
907     ": 2slip [ call ] [ ] [ ] tri* ;"
908     ""
909     ": nip   [ drop ] [ ] bi* ;"
910     ": 2nip  [ drop ] [ drop ] [ ] tri* ;"
911     ""
912     ": rot"
913     "    [ [ drop ] [      ] [ drop ] tri* ]"
914     "    [ [ drop ] [ drop ] [      ] tri* ]"
915     "    [ [      ] [ drop ] [ drop ] tri* ]"
916     "    3tri ;"
917     ""
918     ": -rot"
919     "    [ [ drop ] [ drop ] [      ] tri* ]"
920     "    [ [      ] [ drop ] [ drop ] tri* ]"
921     "    [ [ drop ] [      ] [ drop ] tri* ]"
922     "    3tri ;"
923     ""
924     ": spin"
925     "    [ [ drop ] [ drop ] [      ] tri* ]"
926     "    [ [ drop ] [      ] [ drop ] tri* ]"
927     "    [ [      ] [ drop ] [ drop ] tri* ]"
928     "    3tri ;"
929 } ;
930
931 ARTICLE: "spread-combinators" "Spread combinators"
932 "The spread combinators apply multiple quotations to multiple values. The " { $snippet "*" } " suffix signifies spreading."
933 $nl
934 "Two quotations:"
935 { $subsection bi* }
936 { $subsection 2bi* }
937 "Three quotations:"
938 { $subsection tri* }
939 { $subsection 2tri* }
940 "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:"
941 { $code
942     "! First alternative; uses dip"
943     "[ [ 1 + ] dip 1 - ] dip 2 *"
944     "! Second alternative: uses tri*"
945     "[ 1 + ] [ 1 - ] [ 2 * ] tri*"
946 }
947 "A generalization of the above combinators to any number of quotations can be found in " { $link "combinators" } "."
948 { $subsection "spread-shuffle-equivalence" } ;
949
950 ARTICLE: "apply-combinators" "Apply combinators"
951 "The apply combinators apply a single quotation to multiple values. The " { $snippet "@" } " suffix signifies application."
952 $nl
953 "Two quotations:"
954 { $subsection bi@ }
955 { $subsection 2bi@ }
956 "Three quotations:"
957 { $subsection tri@ }
958 { $subsection 2tri@ }
959 "A pair of utility words built from " { $link bi@ } ":"
960 { $subsection both? }
961 { $subsection either? } ;
962
963 ARTICLE: "slip-keep-combinators" "Retain stack combinators"
964 "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."
965 $nl
966 "The dip combinators invoke the quotation at the top of the stack, hiding the values underneath:"
967 { $subsection dip }
968 { $subsection 2dip }
969 { $subsection 3dip }
970 { $subsection 4dip }
971 "The slip combinators invoke a quotation further down on the stack. They are most useful for implementing other combinators:"
972 { $subsection slip }
973 { $subsection 2slip }
974 { $subsection 3slip }
975 "The keep combinators invoke a quotation which takes a number of values off the stack, and then they restore those values:"
976 { $subsection keep }
977 { $subsection 2keep }
978 { $subsection 3keep } ;
979
980 ARTICLE: "curried-dataflow" "Curried dataflow combinators"
981 "Curried cleave combinators:"
982 { $subsection bi-curry }
983 { $subsection tri-curry }
984 "Curried spread combinators:"
985 { $subsection bi-curry* }
986 { $subsection tri-curry* }
987 "Curried apply combinators:"
988 { $subsection bi-curry@ }
989 { $subsection tri-curry@ }
990 { $see-also "dataflow-combinators" } ;
991
992 ARTICLE: "compositional-examples" "Examples of compositional combinator usage"
993 "Consider printing the same message ten times:"
994 { $code ": print-10 ( -- ) 10 [ \"Hello, world.\" print ] times ;" }
995 "if we wanted to abstract out the message into a parameter, we could keep it on the stack between iterations:"
996 { $code ": print-10 ( message -- ) 10 [ dup print ] times drop ;" }
997 "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:"
998 { $code ": subtract-n ( seq n -- seq' ) swap [ over - ] map nip ;" }
999 "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 } ":"
1000 { $example
1001   "USING: kernel math prettyprint sequences ;"
1002   ": subtract-n ( seq n -- seq' ) [ - ] curry map ;"
1003   "{ 10 20 30 } 5 subtract-n ."
1004   "{ 5 15 25 }"
1005 }
1006 "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" } "."
1007 $nl
1008 "One way to write this is with a pair of " { $link swap } "s:"
1009 { $code ": n-subtract ( n seq -- seq' ) swap [ swap - ] curry map ;" }
1010 "Since this pattern comes up often, " { $link with } " encapsulates it:"
1011 { $example
1012   "USING: kernel math prettyprint sequences ;"
1013   ": n-subtract ( n seq -- seq' ) [ - ] with map ;"
1014   "30 { 10 20 30 } n-subtract ."
1015   "{ 20 10 0 }"
1016 }
1017 { $see-also "fry.examples" } ;
1018
1019 ARTICLE: "compositional-combinators" "Compositional combinators"
1020 "Certain combinators transform quotations to produce a new quotation."
1021 { $subsection "compositional-examples" }
1022 "Fundamental operations:"
1023 { $subsection curry }
1024 { $subsection compose }
1025 "Derived operations:"
1026 { $subsection 2curry }
1027 { $subsection 3curry }
1028 { $subsection with }
1029 { $subsection prepose }
1030 "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."
1031 $nl
1032 "Curried dataflow combinators can be used to build more complex dataflow by combining cleave, spread and apply patterns in various ways."
1033 { $subsection "curried-dataflow" }
1034 "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." ;
1035
1036 ARTICLE: "implementing-combinators" "Implementing combinators"
1037 "The following pair of words invoke words and quotations reflectively:"
1038 { $subsection call }
1039 { $subsection execute }
1040 "These words are used to implement combinators. Note that combinator definitions must be followed by the " { $link POSTPONE: inline } " declaration in order to compile in the optimizing compiler; for example:"
1041 { $code
1042     ": keep ( x quot -- x )"
1043     "    over [ call ] dip ; inline"
1044 }
1045 "Word inlining is documented in " { $link "declarations" } "." ;
1046
1047 ARTICLE: "booleans" "Booleans"
1048 "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."
1049 { $subsection f }
1050 { $subsection t }
1051 "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."
1052 $nl
1053 "Here is the " { $link f } " object:"
1054 { $example "f ." "f" }
1055 "Here is the " { $link f } " class:"
1056 { $example "\\ f ." "POSTPONE: f" }
1057 "They are not equal:"
1058 { $example "f \\ f = ." "f" }
1059 "Here is an array containing the " { $link f } " object:"
1060 { $example "{ f } ." "{ f }" }
1061 "Here is an array containing the " { $link f } " class:"
1062 { $example "{ POSTPONE: f } ." "{ POSTPONE: f }" }
1063 "The " { $link f } " object is an instance of the " { $link f } " class:"
1064 { $example "USE: classes" "f class ." "POSTPONE: f" }
1065 "The " { $link f } " class is an instance of " { $link word } ":"
1066 { $example "USE: classes" "\\ f class ." "word" }
1067 "On the other hand, " { $link t } " is just a word, and there is no class which it is a unique instance of."
1068 { $example "t \\ t eq? ." "t" }
1069 "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* } "." ;
1070
1071 ARTICLE: "conditionals-boolean-equivalence" "Expressing conditionals with boolean logic"
1072 "Certain simple conditional forms can be expressed in a simpler manner using boolean logic."
1073 $nl
1074 "The following two lines are equivalent:"
1075 { $code "[ drop f ] unless" "swap and" }
1076 "The following two lines are equivalent:"
1077 { $code "[ ] [ ] ?if" "swap or" }
1078 "The following two lines are equivalent, where " { $snippet "L" } " is a literal:"
1079 { $code "[ L ] unless*" "L or" } ;
1080
1081 ARTICLE: "conditionals" "Conditionals and logic"
1082 "The basic conditionals:"
1083 { $subsection if }
1084 { $subsection when }
1085 { $subsection unless }
1086 "Forms abstracting a common stack shuffle pattern:"
1087 { $subsection if* }
1088 { $subsection when* }
1089 { $subsection unless* }
1090 "Another form abstracting a common stack shuffle pattern:"
1091 { $subsection ?if }
1092 "Sometimes instead of branching, you just need to pick one of two values:"
1093 { $subsection ? }
1094 "There are some logical operations on booleans:"
1095 { $subsection >boolean }
1096 { $subsection not }
1097 { $subsection and }
1098 { $subsection or }
1099 { $subsection xor }
1100 { $subsection "conditionals-boolean-equivalence" }
1101 "See " { $link "combinators" } " for forms which abstract away common patterns involving multiple nested branches."
1102 { $see-also "booleans" "bitwise-arithmetic" both? either? } ;
1103
1104 ARTICLE: "equality" "Equality"
1105 "There are two distinct notions of “sameness” when it comes to objects."
1106 $nl
1107 "You can test if two references point to the same object (" { $emphasis "identity comparison" } "). This is rarely used; it is mostly useful with large, mutable objects where the object identity matters but the value is transient:"
1108 { $subsection eq? }
1109 "You can test if two objects are equal in a domain-specific sense, usually by being instances of the same class, and having equal slot values (" { $emphasis "value comparison" } "):"
1110 { $subsection = }
1111 "A third form of equality is provided by " { $link number= } ". It compares numeric value while disregarding types."
1112 $nl
1113 "Custom value comparison methods for use with " { $link = } " can be defined on a generic word:"
1114 { $subsection equal? }
1115 "Utility class:"
1116 { $subsection identity-tuple }
1117 "An object can be cloned; the clone has distinct identity but equal value:"
1118 { $subsection clone } ;
1119
1120 ARTICLE: "assertions" "Assertions"
1121 "Some words to make assertions easier to enforce:"
1122 { $subsection assert }
1123 { $subsection assert= } ;
1124
1125 ARTICLE: "dataflow-combinators" "Data flow combinators"
1126 "Data flow combinators pass values between quotations:"
1127 { $subsection "slip-keep-combinators" }
1128 { $subsection "cleave-combinators" }
1129 { $subsection "spread-combinators" }
1130 { $subsection "apply-combinators" }
1131 { $see-also "curried-dataflow" } ;
1132
1133 ARTICLE: "dataflow" "Data and control flow"
1134 { $subsection "evaluator" }
1135 { $subsection "words" }
1136 { $subsection "effects" }
1137 { $subsection "booleans" }
1138 { $subsection "shuffle-words" }
1139 "A central concept in Factor is that of a " { $emphasis "combinator" } ", which is a word taking code as input."
1140 { $subsection "dataflow-combinators" }
1141 { $subsection "conditionals" }
1142 { $subsection "looping-combinators" }
1143 { $subsection "compositional-combinators" }
1144 { $subsection "combinators" }
1145 "More combinators are defined for working on data structures, such as " { $link "sequences-combinators" } " and " { $link "assocs-combinators" } "."
1146 $nl
1147 "Advanced topics:"
1148 { $subsection "assertions" }
1149 { $subsection "implementing-combinators" }
1150 { $subsection "macros" }
1151 { $subsection "errors" }
1152 { $subsection "continuations" } ;
1153
1154 ABOUT: "dataflow"
1155