]> gitweb.factorcode.org Git - factor.git/blob - core/assocs/assocs-docs.factor
Merge branch 'master' into experimental (untested!)
[factor.git] / core / assocs / assocs-docs.factor
1 ! Copyright (C) 2007 Daniel Ehrenberg, Slava Pestov, and Doug Coleman
2 ! See http://factorcode.org/license.txt for BSD license.
3 USING: help.markup help.syntax kernel sequences
4 sequences.private namespaces math quotations ;
5 IN: assocs
6
7 ARTICLE: "alists" "Association lists"
8 "An " { $emphasis "association list" } ", abbreviated " { $emphasis "alist" } ", is an association represented as a sequence where all elements are key/value pairs. The " { $link sequence } " mixin is an instance of the " { $link assoc } " mixin, hence all sequences support the " { $link "assocs-protocol" } " in this way."
9 $nl
10 "While not an association list, note that " { $link f } " also implements the associative mapping protocol in a trivial way; it is an immutable assoc with no entries."
11 $nl
12 "An alist is slower to search than a hashtable for a large set of associations. The main advantage of an association list is that the elements are ordered; also sometimes it is more convenient to construct an association list with sequence words than to construct a hashtable with association words. Much of the time, hashtables are more appropriate. See " { $link "hashtables" } "."
13 $nl
14 "There is no special syntax for literal alists since they are just sequences; in practice, literals look like so:"
15 { $code "{" "    { key1 value1 }" "    { key2 value2 }" "}" }
16 "To make an assoc into an alist:"
17 { $subsection >alist } ;
18
19 ARTICLE: "enums" "Enumerations"
20 "An enumeration provides a view of a sequence as an assoc mapping integer indices to elements:"
21 { $subsection enum }
22 { $subsection <enum> }
23 "Inverting a permutation using enumerations:"
24 { $example "USING: assocs sorting prettyprint ;" ": invert <enum> >alist sort-values keys ;" "{ 2 0 4 1 3 } invert ." "{ 1 3 0 4 2 }" } ;
25
26 HELP: enum
27 { $class-description "An associative structure which wraps a sequence and maps integers to the corresponding elements of the sequence."
28 $nl
29 "Enumerations are mutable; note that deleting a key calls " { $link delete-nth } ", which results in all subsequent elements being shifted down." } ;
30
31 HELP: <enum>
32 { $values { "seq" sequence } { "enum" enum } }
33 { $description "Creates a new enumeration." } ;
34
35 ARTICLE: "assocs-protocol" "Associative mapping protocol"
36 "All associative mappings must be instances of a mixin class:"
37 { $subsection assoc }
38 { $subsection assoc? }
39 "All associative mappings must implement methods on the following generic words:"
40 { $subsection at* }
41 { $subsection assoc-size }
42 { $subsection >alist }
43 "Mutable assocs should implement the following additional words:"
44 { $subsection set-at }
45 { $subsection delete-at }
46 { $subsection clear-assoc }
47 "The following three words are optional:"
48 { $subsection value-at* }
49 { $subsection new-assoc }
50 { $subsection assoc-like }
51 "Assocs should also implement methods on the " { $link clone } ", " { $link equal? } " and " { $link hashcode* } " generic words. Two utility words will help with the implementation of the last two:"
52 { $subsection assoc= }
53 { $subsection assoc-hashcode }
54 "Finally, assoc classes should define a word for converting other types of assocs; conventionally, such words are named " { $snippet ">" { $emphasis "class" } } " where " { $snippet { $emphasis "class" } } " is the class name. Such a word can be implemented using a utility:"
55 { $subsection assoc-clone-like } ;
56
57 ARTICLE: "assocs-lookup" "Lookup and querying of assocs"
58 "Utility operations built up from the " { $link "assocs-protocol" } ":"
59 { $subsection key? }
60 { $subsection at }
61 { $subsection assoc-empty? }
62 { $subsection keys }
63 { $subsection values }
64 { $subsection assoc-stack }
65 { $see-also at* assoc-size } ;
66
67 ARTICLE: "assocs-values" "Transposed assoc operations"
68 "Most assoc words take a key and find the corresponding value. The following words take a value and find the corresponding key:"
69 { $subsection value-at }
70 { $subsection value-at* }
71 { $subsection value? }
72 "With most assoc implementations, these words runs in linear time, proportional to the number of entries in the assoc. For fast value lookups, use " { $vocab-link "biassocs" } "." ;
73
74 ARTICLE: "assocs-sets" "Set-theoretic operations on assocs"
75 "It is often useful to use the keys of an associative mapping as a set, exploiting the constant or logarithmic lookup time of most implementations (" { $link "alists" } " being a notable exception)."
76 { $subsection assoc-subset? }
77 { $subsection assoc-intersect }
78 { $subsection update }
79 { $subsection assoc-union }
80 { $subsection assoc-diff }
81 { $subsection remove-all }
82 { $subsection substitute }
83 { $subsection substitute-here }
84 { $subsection extract-keys }
85 { $see-also key? assoc-contains? assoc-all? "sets" } ;
86
87 ARTICLE: "assocs-mutation" "Storing keys and values in assocs"
88 "Utility operations built up from the " { $link "assocs-protocol" } ":"
89 { $subsection delete-at* }
90 { $subsection rename-at }
91 { $subsection change-at }
92 { $subsection at+ }
93 { $subsection inc-at }
94 { $see-also set-at delete-at clear-assoc push-at } ;
95
96 ARTICLE: "assocs-conversions" "Associative mapping conversions"
97 "Converting to other assocs:"
98 { $subsection assoc-clone-like }
99 "Combining a sequence of assocs into a single assoc:"
100 { $subsection assoc-combine }
101 "Creating an assoc from key/value sequences:"
102 { $subsection zip }
103 "Creating key/value sequences from an assoc:"
104 { $subsection unzip }
105 ;
106
107 ARTICLE: "assocs-combinators" "Associative mapping combinators"
108 "The following combinators can be used on any associative mapping."
109 $nl
110 "The " { $link assoc-find } " combinator is part of the " { $link "assocs-protocol" } " and must be implemented once for each class of assoc. All other combinators are implemented in terms of this combinator."
111 $nl
112 "The standard functional programming idioms:"
113 { $subsection assoc-each }
114 { $subsection assoc-find }
115 { $subsection assoc-map }
116 { $subsection assoc-push-if }
117 { $subsection assoc-filter }
118 { $subsection assoc-contains? }
119 { $subsection assoc-all? }
120 "Additional combinators:"
121 { $subsection cache }
122 { $subsection map>assoc }
123 { $subsection assoc>map }
124 { $subsection assoc-map-as }
125 { $subsection search-alist }
126 "Utility word:"
127 { $subsection assoc-pusher } ;
128
129 ARTICLE: "assocs" "Associative mapping operations"
130 "An " { $emphasis "associative mapping" } ", abbreviated " { $emphasis "assoc" } ", is a collection of key/value pairs which provides efficient lookup and storage indexed by key."
131 $nl
132 "Words used for working with assocs are in the " { $vocab-link "assocs" } " vocabulary."
133 $nl
134 "Associative mappings implement a protocol:"
135 { $subsection "assocs-protocol" }
136 "A large set of utility words work on any object whose class implements the associative mapping protocol."
137 { $subsection "assocs-lookup" }
138 { $subsection "assocs-values" }
139 { $subsection "assocs-mutation" }
140 { $subsection "assocs-combinators" }
141 { $subsection "assocs-sets" }
142 { $subsection "assocs-conversions" } ;
143
144 ABOUT: "assocs"
145
146 HELP: assoc
147 { $class-description "A mixin class whose instances are associative mappings. Custom implementations of the assoc protocol should be declared as instances of this mixin for all assoc functionality to work correctly:"
148     { $code "INSTANCE: avl-tree assoc" }
149 } ;
150
151 HELP: at*
152 { $values { "key" "an object to look up in the assoc" } { "assoc" assoc } { "value/f" "the value associated to the key, or " { $link f } " if the key is not present in the assoc" } { "?" "a boolean indicating if the key was present" } }
153 { $contract "Looks up the value associated with a key. The boolean flag can decide between the case of a missing value, and a value of " { $link f } "." } ;
154
155 HELP: set-at
156 { $values { "value" "a value" } { "key" "a key to add" } { "assoc" assoc } }
157 { $contract "Stores the key/value pair into the assoc." }
158 { $side-effects "assoc" } ;
159
160 HELP: new-assoc
161 { $values { "capacity" "a non-negative integer" } { "exemplar" assoc } { "newassoc" assoc } }
162 { $contract "Creates a new assoc of the same size as " { $snippet "exemplar" } " which can hold " { $snippet "capacity" } " entries before growing." } ;
163
164 HELP: assoc-find
165 { $values { "assoc" assoc } { "quot" { $quotation "( key value -- ? )" } } { "key" "the successful key, or f" } { "value" "the successful value, or f" } { "?" "a boolean" } }
166 { $description "Applies a predicate quotation to each entry in the assoc. Returns the key and value that the quotation succeeds on, or " { $link f } " for both if the quotation fails. It also returns a boolean describing whether there was anything found; this can be used to distinguish between a key and a value equal to " { $link f } ", or nothing being found." } ;
167
168 HELP: clear-assoc
169 { $values { "assoc" assoc } }
170 { $contract "Removes all entries from the assoc."  }
171 { $side-effects "assoc" } ;
172
173 HELP: delete-at
174 { $values { "key" "a key" } { "assoc" assoc } }
175 { $contract "Removes an entry from the assoc." }
176 { $side-effects "assoc" } ;
177
178 HELP: assoc-size
179 { $values { "assoc" assoc } { "n" "a non-negative integer" } }
180 { $contract "Outputs the number of entries stored in the assoc." } ;
181
182 HELP: assoc-like
183 { $values { "assoc" assoc } { "exemplar" assoc } { "newassoc" "a new assoc" } }
184 { $contract "Creates a new assoc having the same entries as  "{ $snippet "assoc" } " and the same type as " { $snippet "exemplar" } "." } ;
185
186 HELP: assoc-empty?
187 { $values { "assoc" assoc } { "?" "a boolean" } }
188 { $description "Tests if the assoc contains no entries." } ;
189
190 HELP: key?
191 { $values { "key" object } { "assoc" assoc } { "?" "a boolean" } }
192 { $description "Tests if an assoc contains a key." } ;
193
194 { at at* key? } related-words
195
196 HELP: at
197 { $values { "key" "an object" } { "assoc" assoc } { "value/f" "the value associated to the key, or " { $link f } " if the key is not present in the assoc" } }
198 { $description "Looks up the value associated with a key. This word makes no distinction between a missing value and a value set to " { $link f } "; if the difference is important, use " { $link at* } "." } ;
199
200 HELP: assoc-each
201 { $values { "assoc" assoc } { "quot" { $quotation "( key value -- )" } } }
202 { $description "Applies a quotation to each entry in the assoc." }
203 { $examples
204     { $example
205         "USING: assocs kernel math prettyprint ;"
206         "H{ { \"bananas\" 5 } { \"apples\" 42 } { \"pears\" 17 } }"
207         "0 swap [ nip + ] assoc-each ."
208         "64"
209     }
210 } ;
211
212 HELP: assoc-map
213 { $values { "assoc" assoc } { "quot" { $quotation "( key value -- newkey newvalue )" } } { "newassoc" "a new assoc" } }
214 { $description "Applies the quotation to each entry in the input assoc and collects the results in a new assoc of the same type as the input." }
215 { $examples
216     { $unchecked-example
217         ": discount ( prices n -- newprices )"
218         "    [ - ] curry assoc-map ;"
219         "H{ { \"bananas\" 5 } { \"apples\" 42 } { \"pears\" 17 } }"
220         "2 discount ."
221         "H{ { \"bananas\" 3 } { \"apples\" 39 } { \"pears\" 15 } }"
222     }
223 } ;
224
225 { assoc-map assoc-map-as } related-words
226
227 HELP: assoc-push-if
228 { $values { "accum" "a resizable mutable sequence" } { "quot" { $quotation "( key value -- ? )" } } { "key" object } { "value" object } }
229 { $description "If the quotation yields true when applied to the key/value pair, adds the key/value pair at the end of " { $snippet "accum" } "." } ;
230
231 HELP: assoc-filter
232 { $values { "assoc" assoc } { "quot" { $quotation "( key value -- ? )" } } { "subassoc" "a new assoc" } }
233 { $description "Outputs an assoc of the same type as " { $snippet "assoc" } " consisting of all entries for which the predicate quotation yields true." } ;
234
235 HELP: assoc-contains?
236 { $values { "assoc" assoc } { "quot" { $quotation "( key value -- ? )" } } { "?" "a boolean" } }
237 { $description "Tests if the assoc contains an entry satisfying a predicate by applying the quotation to each entry in turn. Iteration stops if an entry is found for which the quotation outputs a true value." } ;
238
239 HELP: assoc-all?
240 { $values { "assoc" assoc } { "quot" { $quotation "( key value -- ? )" } } { "?" "a boolean" } }
241 { $description "Tests if all entries in the assoc satisfy a predicate by applying the quotation to each entry in turn. a predicate quotation to entry in the assoc. Iteration stops if an entry is found for which the quotation outputs " { $link f } ". If the assoc is empty, always outputs " { $link t } "." } ;
242
243 HELP: assoc-subset?
244 { $values { "assoc1" assoc } { "assoc2" assoc } { "?" "a new assoc" } }
245 { $description "Tests if " { $snippet "assoc2" } " contains all key/value pairs of " { $snippet "assoc1" } "." } ;
246
247 HELP: assoc=
248 { $values { "assoc1" assoc } { "assoc2" assoc } { "?" "a boolean" } }
249 { $description "Tests if two assocs contain the same entries. Unlike " { $link = } ", the two assocs may be of different types." }
250 { $notes "Assoc implementations should define a method for the " { $link equal? } " generic word which calls this word after checking that both inputs have the same type." } ;
251
252 HELP: assoc-hashcode
253 { $values { "n" "a non-negative integer" } { "assoc" assoc } { "code" integer } }
254 { $description "Computes a hashcode for an assoc, such that equal assocs will have the same hashcode." }
255 { $notes "Custom assoc implementations should use this word to implement a method for the " { $link hashcode* } " generic word." } ;
256
257 HELP: assoc-stack
258 { $values { "key" "a key" } { "seq" "a sequence of assocs" } { "value" "a value or " { $link f } } }
259 { $description "Searches for the key in successive elements of the sequence, starting from the end. If an assoc containing the key is found, the associated value is output. If no assoc contains the key, outputs " { $link f } "." }
260 { $notes "This word is used to implement abstractions such as nested scopes; if the sequence is a stack represented by a vector, then the most recently pushed assoc -- the innermost scope -- will be searched first." } ;
261
262 HELP: value-at*
263 { $values { "value" "an object" } { "assoc" assoc } { "key/f" "the key associated to the value, or " { $link f } } { "?" "a boolean" } }
264 { $description "Looks up the key associated with a value. The boolean flag can decide beteen the case of a missing key, and a key of " { $link f } "." } ;
265
266 HELP: value-at
267 { $values { "value" "an object" } { "assoc" assoc } { "key/f" "the key associated to the value, or " { $link f } } }
268 { $description "Looks up the key associated with a value. No distinction is made between a missing key and a key set to " { $link f } "." } ;
269
270 HELP: value?
271 { $values { "value" "an object" } { "assoc" assoc } { "?" "a boolean" } }
272 { $description "Tests if an assoc contains at least one key with the given value." } ;
273
274 HELP: delete-at*
275 { $values { "key" "a key" } { "assoc" assoc } { "old" "the previous value or " { $link f } } { "?" "a boolean" } }
276 { $description "Removes an entry from the assoc and outputs the previous value together with a boolean indicating whether it was present." }
277 { $side-effects "assoc" } ;
278
279 HELP: rename-at
280 { $values { "newkey" object } { "key" object } { "assoc" assoc } }
281 { $description "Removes the values associated to " { $snippet "key" } " and re-adds it as " { $snippet "newkey" } ". Does nothing if the assoc does not contain " { $snippet "key" } "." }
282 ;
283
284 HELP: keys
285 { $values { "assoc" assoc } { "keys" "an array of keys" } }
286 { $description "Outputs an array of all keys in the assoc." } ;
287
288 HELP: values
289 { $values { "assoc" assoc } { "values" "an array of values" } }
290 { $description "Outputs an array of all values in the assoc." } ;
291
292 { keys values } related-words
293
294 HELP: assoc-intersect
295 { $values { "assoc1" assoc } { "assoc2" assoc } { "intersection" "a new assoc" } }
296 { $description "Outputs an assoc consisting of all entries from " { $snippet "assoc2" } " such that the key is also present in " { $snippet "assoc1" } "." }
297 { $notes "The values of the keys in " { $snippet "assoc1" } " are disregarded, so this word is usually used for set-theoretic calculations where the assoc in question either has dummy sentinels as values, or the values equal the keys." } ;
298
299 HELP: update
300 { $values { "assoc1" assoc } { "assoc2" assoc } }
301 { $description "Adds all entries from " { $snippet "assoc2" } " to " { $snippet "assoc1" } "." }
302 { $side-effects "assoc1" } ;
303
304 HELP: assoc-union
305 { $values { "assoc1" assoc } { "assoc2" assoc } { "union" "a new assoc" } }
306 { $description "Outputs a assoc consisting of all entries from " { $snippet "assoc1" } " and " { $snippet "assoc2" } ", with entries from " { $snippet "assoc2" } " taking precedence in case the corresponding values are not equal." } ;
307
308 HELP: assoc-diff
309 { $values { "assoc1" assoc } { "assoc2" assoc } { "diff" "a new assoc" } }
310 { $description "Outputs an assoc consisting of all entries from " { $snippet "assoc1" } " whose key is not contained in " { $snippet "assoc2" } "." } 
311 ;
312 HELP: remove-all
313 { $values { "assoc" assoc } { "seq" "a sequence" } { "subseq" "a new sequence" } }
314 { $description "Constructs a sequence consisting of all elements in " { $snippet "seq" } " which do not appear as keys in " { $snippet "assoc" } "." }
315 { $notes "The values of the keys in the assoc are disregarded, so this word is usually used for set-theoretic calculations where the assoc in question either has dummy sentinels as values, or the values equal the keys." }
316 { $side-effects "assoc" } ;
317
318 HELP: substitute-here
319 { $values { "seq" "a mutable sequence" } { "assoc" assoc } }
320 { $description "Replaces elements of " { $snippet "seq" } " which appear as keys in " { $snippet "assoc" } " with the corresponding values, acting as the identity on all other elements." }
321 { $errors "Throws an error if " { $snippet "assoc" } " contains values whose types are not permissible in " { $snippet "seq" } "." }
322 { $side-effects "seq" } ;
323
324 HELP: substitute
325 { $values { "seq" sequence } { "assoc" assoc } { "newseq" sequence } }
326 { $description "Creates a new sequence where elements of " { $snippet "seq" } " which appear as keys in " { $snippet "assoc" } " are replaced by the corresponding values, and all other elements are unchanged." } ;
327
328 HELP: cache
329 { $values { "key" "a key" } { "assoc" assoc } { "quot" { $quotation "( key -- value )" } } { "value" "a previously-retained or freshly-computed value" } }
330 { $description "If the key is present in the assoc, outputs the associated value, otherwise calls the quotation to produce a value and stores the key/value pair into the assoc." }
331 { $side-effects "assoc" } ;
332
333 HELP: map>assoc
334 { $values { "seq" "a sequence" } { "quot" { $quotation "( elt -- key value )" } } { "exemplar" assoc } { "assoc" "a new assoc" } }
335 { $description "Applies the quotation to each element of the sequence, and collects the keys and values into a new assoc having the same type as " { $snippet "exemplar" } "." } ;
336
337 HELP: assoc>map
338 { $values { "assoc" assoc } { "quot" { $quotation "( key value -- elt )" } } { "exemplar" "a sequence" } { "seq" "a new sequence" } }
339 { $description "Applies the quotation to each entry of the assoc and collects the results into a new sequence of the same type as the exemplar." } ;
340
341 HELP: change-at
342 { $values { "key" object } { "assoc" assoc } { "quot" { $quotation "( value -- newvalue )" } } }
343 { $description "Applies the quotation to the value associated with " { $snippet "key" } ", storing the new value back in the assoc." }
344 { $side-effects "assoc" } ;
345
346 { change-at change-nth change } related-words
347
348 HELP: at+
349 { $values { "n" number } { "key" object } { "assoc" assoc } }
350 { $description "Adds " { $snippet "n" } " to the value associated with " { $snippet "key" } "; if there is no value, stores " { $snippet "n" } ", thus behaving as if the value was 0." }
351 { $side-effects "assoc" } ;
352
353 HELP: inc-at
354 { $values { "key" object } { "assoc" assoc } }
355 { $description "Adds 1 to the value associated with " { $snippet "key" } "; if there is no value, stores 1." }
356 { $side-effects "assoc" } ;
357
358 HELP: >alist
359 { $values { "assoc" assoc } { "newassoc" "an array of key/value pairs" } }
360 { $contract "Converts an associative structure into an association list." }
361 { $notes "The " { $link assoc } " mixin has a default implementation for this generic word which constructs the association list by iterating over the assoc with " { $link assoc-find } "." } ;
362
363 HELP: assoc-clone-like
364 { $values
365      { "assoc" assoc } { "exemplar" assoc }
366      { "newassoc" assoc } }
367 { $description "Outputs a newly-allocated assoc with the same elements as " { $snippet "assoc" } "." }
368 { $examples { $example "USING: prettyprint assocs hashtables ;" "H{ { 1 2 } { 3 4 } } { } assoc-clone-like ." "{ { 1 2 } { 3 4 } }" } } ;
369
370 HELP: assoc-combine
371 { $values
372      { "seq" "a sequence of assocs" }
373      { "union" assoc } }
374 { $description "Takes the union of all of the " { $snippet "assocs" } " in " { $snippet "seq" } "." }
375 { $examples { $example "USING: prettyprint assocs ;" "{ H{ { 1 2 } } H{ { 3 4 } } } assoc-combine ." "H{ { 1 2 } { 3 4 } }" } } ;
376
377 HELP: assoc-map-as
378 { $values
379      { "assoc" assoc } { "quot" quotation } { "exemplar" assoc }
380      { "newassoc" assoc } }
381 { $description "Applies the quotation to each entry in the input assoc and collects the results in a new assoc of the stame type as the exemplar." }
382 { $examples { $example "USING: prettyprint assocs hashtables math ;" " H{ { 1 2 } { 3 4 } } [ sq ] { } assoc-map-as ." "{ { 1 4 } { 3 16 } }" } } ;
383
384 HELP: assoc-pusher
385 { $values
386      { "quot" "a predicate quotation" }
387      { "quot'" quotation } { "accum" assoc } }
388 { $description "Creates a new " { $snippet "assoc" } " to accumulate the key/value pairs which return true for a predicate.  Returns a new quotation which accepts a pair of object to be tested and stored in the accumulator if the test yields true. The accumulator is left on the stack for convenience." }
389 { $example "! Find only the pairs that sum to 5:" "USING: prettyprint assocs math kernel ;"
390            "{ { 1 2 } { 2 3 } { 3 4 } } [ + 5 = ] assoc-pusher [ assoc-each ] dip ."
391            "V{ { 2 3 } }"
392 }
393 { $notes "Used to implement the " { $link assoc-filter } " word." } ;
394
395
396 HELP: extract-keys
397 { $values
398      { "seq" sequence } { "assoc" assoc }
399      { "subassoc" assoc } }
400 { $description "Outputs an new " { $snippet "assoc" } " with key/value pairs whose keys match the elements in the input " { $snippet "seq" } "." }
401 { $examples
402     { $example "USING: prettyprint assocs ;"
403                "{ 1 3 } { { 1 10 } { 2 20 } { 3 30 } } extract-keys ."
404                "{ { 1 10 } { 3 30 } }"
405     }
406 } ;
407
408 HELP: push-at
409 { $values
410      { "value" object } { "key" object } { "assoc" assoc } }
411 { $description "Pushes the " { $snippet "value" } " onto a " { $snippet "vector" } " stored at the " { $snippet "key" } " in the " { $snippet "assoc" } ". If the " { $snippet "key" } " does not yet exist, creates a new " { $snippet "vector" } " at that " { $snippet "key" } " and pushes the " { $snippet "value" } "." }
412 { $examples { $example  "USING: prettyprint assocs kernel ;"
413 "H{ { \"cats\" V{ \"Mittens\" } } } \"Mew\" \"cats\" pick push-at ."
414 "H{ { \"cats\" V{ \"Mittens\" \"Mew\" } } }"
415 } } ;
416
417 HELP: search-alist
418 { $values
419      { "key" object } { "alist" "an array of key/value pairs" }
420      { "pair/f" "a key/value pair" } { "i/f" integer } }
421 { $description "Performs an in-order traversal of a " { $snippet "alist" } " and stops when the key is matched or the end of the " { $snippet "alist" } " has been reached. If there is no match, both outputs are " { $link f } "." }
422 { $examples { $example "USING: prettyprint assocs kernel ;"
423                         "3 { { 1 2 } { 3 4 } } search-alist [ . ] bi@"
424                        "{ 3 4 }\n1"
425             } { $example "USING: prettyprint assocs kernel ;"
426                        "6 { { 1 2 } { 3 4 } } search-alist [ . ] bi@"
427                        "f\nf"
428             }
429 } ;
430
431 HELP: unzip
432 { $values
433      { "assoc" assoc }
434      { "keys" sequence } { "values" sequence } }
435 { $description "Outputs an array of keys and an array of values of the input " { $snippet "assoc" } "." }
436 { $examples 
437     { $example "USING: prettyprint assocs kernel ;"
438                "{ { 1 4 } { 2 5 } { 3 6 } } unzip [ . ] bi@"
439                "{ 1 2 3 }\n{ 4 5 6 }" 
440     }
441 } ;
442
443 HELP: zip
444 { $values
445      { "keys" sequence } { "values" sequence }
446      { "alist" "an array of key/value pairs" } }
447 { $description "Combines two sequences pairwise into a single sequence of key/value pairs." }
448 { $examples 
449     { $example "" "USING: prettyprint assocs ;"
450                "{ 1 2 3 } { 4 5 6 } zip ."
451                "{ { 1 4 } { 2 5 } { 3 6 } }"
452     }
453 } ;
454 { unzip zip } related-words