summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGravatar John Cowan 2021-10-01 19:29:47 -0400
committerGravatar John Cowan 2021-10-01 19:29:47 -0400
commit9479632370ff473c9c802e18710f39bbb643e9c7 (patch)
tree43e33b82abb33b0355b772e9ba60b20cf79cb642
parenttypo, -comparator can return #f (diff)
starting draft 3
-rw-r--r--srfi-225.html151
1 files changed, 59 insertions, 92 deletions
diff --git a/srfi-225.html b/srfi-225.html
index 6b1dc8a..c2ebc0c 100644
--- a/srfi-225.html
+++ b/srfi-225.html
@@ -33,8 +33,6 @@ of the object is. Such an object is called a <em>dictionary</em> in this SRFI.<
<h2 id="issues">Issues</h2>
-
-
<p>dict=?, dict&lt;?, etc. Compare dictionaries for equality, subset, etc.
A value comparator is passed in.</p>
@@ -55,43 +53,27 @@ Returns subsets whose keys are in a certain interval specified by upper and lowe
<p>Until recently there was only one universally available mechanism for managing key-value pairs: alists. Most Schemes also support hash tables, but until R6RS there was no standard interface to them, and many implementations do not provide that interface.</p>
<p>Now, however, the number of such mechanisms is growing. In addition to both R6RS and R7RS hash tables, there are persistent ordered and hashed mappings from SRFI 146 and ordered key-value stores (often on a disk or a remote machine) from SRFI 167.</p>
<p>It’s inconvenient for users if SRFIs or other libraries have to insist on accepting only a specific type of dictionary. This SRFI exposes a number of accessors, mutators, and other procedures that can be called on any dictionary, provided that a <em>dictionary type descriptor</em> (DTD, with apologies to SGML and XML users) is available for it: either exported from this SRFI, or from other SRFIs or libraries, or created by the user. DTDs are of an unspecified type.</p>
-<p>This in turn requires that the DTD provides a predicate that can recognize its dictionaries, plus at least these primitive operations: create an empty dictionary from a comparator; determine a dictionary’s current size; reference, update, or insert an element of the dictionary depending on its current contents; and process all the elements using a procedure invoked for its side effects.</p>
-<p>By using the procedures of this SRFI, a procedure can take a DTD and a dictionary as an argument and make flexible use of the dictionary without knowing its exact type.</p>
-<p>Note that dictionaries must still be constructed using type-specific constructors, as the required and optional arguments differ in each case.</p>
+<p>This in turn requires that the DTD provides a predicate that can recognize its dictionaries, plus at least these primitive operations: determine a dictionary’s current size; reference, update, or insert an element of the dictionary depending on its current contents; process all the elements using a procedure invoked for its side effects; and return the comparator of the dictionary or <code>#f</code> if none was provided when the dictionary was created.</p>
+<p>By using the procedures of this SRFI, a procedure can take a DTD and a dictionary as an argument and make flexible use of the dictionary without knowing its exact type. For the purposes of this SRFI, such a procedure is called a <em>generic procedure</em>.</p>
+<p>However, dictionaries need to be constructed using type-specific constructors, as the required and optional arguments differ in each case. In addition, the dictionary type provided by the caller of a generic procedure doesn't necessarily have the right performance characteristics needed by the generic procedure itself. Consequently there are no <code>make-dict</code>, <code>dict</code>, <code>dict-unfold</code>, <code>dict-copy</code> or similar procedures in this SRFI; by the same token, there are no <code>dict-map</code>, <code>dict-filter</code>, or <code>dict-remove</code> procedures either.</p>
<h2 id="specification">Specification</h2>
<p>We call a specific key-value combination an <em>association</em>. This is why an alist, or association list, is called that; it is a list of associations represented as pairs.</p>
<p>A <em>dictionary</em> is a collection of associations which may be ordered or unordered. In principle an <em>equality predicate</em> is enough, given a key, to find if an association with that key exists in the dictionary. However, for efficiency most dictionaries require an <em>ordering predicate</em> or a <em>hash function</em> as well.
<p>When a key argument is said to be the same as some key of the dictionary, it means that they are the same in the sense of the dictionary’s implicit or explicit equality predicate. It is assumed that no dictionary contains two keys that are the same in this sense.
-Two dictionaries are <i>similar</i> if they are of the same type and have the same equality predicate and the same ordering predicate and/or hash function.</p>
+Two dictionaries are <em>similar</em>g if they are of the same type and have the same equality predicate and the same ordering predicate and/or hash function.</p>
<h3 id="lists-as-dictionaries">Lists as dictionaries</h3>
<p>Lists are supported as dictionaries using the specification in this section. If two keys are the same (in the sense of the specified equality predicate), then all but the first are treated as if they did not exist.</p>
-<p>If <code>plist-dtd</code> (see below) is used with a list, then the list is assumed to be a property list, alternating symbol keys with values. The linear-update mutation operations actually mutate the property list whenever possible. The equality predicate of this type of dictionary is <code>eq?</code>.</p>
+<p>If <code>plist-dtd</code> (see below) is used with a list, then the list is assumed to be a property list, alternating symbol keys with values. Unlike the mutation operations provided by Common Lisp, plists are functionally updated. The equality predicate of this type of dictionary is <code>eq?</code>.</p>
<p>If a list is empty or its car is a pair, then the list can be treated as an alist. New values are added to the beginning of an alist and the new alist is returned; linear-update operations do not mutate the alist, but return an alist that may or may not share storage with the original alist. If an association has been updated, then both the new and the old association may be processed by the whole-dictionary procedures. The examples in this SRFI use alists.</p>
-<p>However, an alist (unlike a hashtable or mapping) does not know which equality predicate its users intend to use on it. Therefore, rather than exporting a single DTD for all alists, this SRFI provides a procedure <code>make-alist-dtd</code> that takes an equality predicate and returns a DTD specialized for manipulation of alists using that predicate.</p>
-<p>In all other cases, lists cannot be treated as dictionaries unless a DTD exists.</p>
+<p>However, an alist (unlike a hashtable or mapping) does not know which equality predicate its users intend to use on it. Therefore, rather than exporting a single DTD for all alists, this SRFI provides a procedure <code>make-alist-dtd</code> that takes an equality predicate and returns a DTD specialized for manipulation of alists using that predicate. For convenience, DTDs for <code>eqv?</code> and <code>equal?</code> are exported.</p>
+<p>In all other cases, lists cannot be treated as dictionaries unless a DTD has been written to handle them.</p>
<h3>Procedures</h3>
<p>Each of the following examples is assumed to be prefixed by the following definitions:</p>
<blockquote><pre>(define dict (list '(1 . 2) '(3 . 4) '(5 . 6)))
(define aed alist-eqv-dtd)
</pre></blockquote>
Consequently, previous examples don't affect later ones.
-<p>The <em>dtd</em> argument is not discussed in the individual procedure descriptions below, but it is an error if invoking the <code>dictionary?</code> procedure that was used to make the DTD on <em>dictionary</em> returns <code>#f</code>.</p>
-<h3 id="constructor">Constructor</h3>
-<p><code>(make-dictionary</code>&nbsp;<em>dtd comparator</em><code>)</code></p>
-<p>Returns an empty dictionary of the type described by the DTD using <em>comparator</em> to specify the dictionary's equality predicate and its ordering predicate and/or hash function.</p>
-<p>If the contents of <em>comparator</em> are inconsistent with the dictionary type, it is an error.
-If the dictionary type does not accept a comparator, <code>#f</code> should be passed instead.</p>
-<p><code>(dict-unfold</code>&nbsp;<em>dtd comparator stop? mapper successor seed</em><code>)</code></p>
-<p>
-Create a new dictionary as if by <code>make-dictionary</code> using
-<em>dtd</em> and <em>comparator</em>. If the result of applying
-the predicate <em>stop?</em> to <em>seed</em> is true, return the dictionary.
-Otherwise, apply the procedure <em>mapper</em> to <em>seed</em>.
-<em>Mapper</em> returns two values, which are inserted into the dictionary
-as the key and the value respectively. Then get a new seed by
-applying the procedure <em>successor</em> to <em>seed</em>, and repeat
-this algorithm.
-</p>
+<p>The <em>dtd</em> argument is not discussed in the individual procedure descriptions below, but it is an error if invoking <code>dictionary?</code> on <em>dtd</em> and <em>dict</em> returns <code>#f</code>.</p>
<h3 id="predicates">Predicates</h3>
<p><code>(dictionary?</code>&nbsp;<em>dtd obj</em><code>)</code></p>
<p>Returns <code>#t</code> if <em>obj</em> answers <code>#t</code> to the type predicate stored in the DTD, and <code>#f</code> otherwise.</p>
@@ -104,6 +86,10 @@ this algorithm.
<blockquote><pre>(dict-contains? aed dict 1) =&gt; #t
(dict-contains? aed dict 2) =&gt; #f</pre></blockquote>
<p>Returns <code>#t</code> if one of the keys of <em>dictionary</em> is the same as <em>key</em>, and <code>#f</code> otherwise.</p>
+<p><code>(dictionary=?</code>&nbsp;<em>= dict1 dict2</em><code>)</code></p>
+<p>Returns <code>#t</code> if the keys of <em>dict1</em> and <em>dict2</em> are the same, and the corresponding values are the same in the sense of the <em>=</em> argument.</p>
+<p><code>(dict-mutable?</code>&nbsp;<em>dtd dict</em><code>)</code></p>
+<p>Returns <code>#t</code> if the underlying dictionary type supports mutations and <code>#f</code> if it supports functional updates.</p>
<h3 id="lookup">Lookup</h3>
<p><code>(dict-ref</code>&nbsp;<em>dtd dictionary key</em> [<em>failure</em> [<em>success</em>] ]<code>)</code></p>
<p>If <em>key</em> is the same as some key of <em>dictionary</em>, then invokes <em>success</em> on the corresponding value and returns its result. If <em>key</em> is not a key of <em>dictionary</em>, then invokes the thunk <em>failure</em> and returns its result. The default value of <em>failure</em> signals an error; the default value of <em>success</em> is the identity procedure.</p>
@@ -113,8 +99,8 @@ this algorithm.
<p>If <em>key</em> is the same as some key of <em>dictionary</em> then returns the corresponding value. If not, then returns <em>default</em>.</p>
<blockquote><pre>(dict-ref/default aed dict 1 #f) =&gt; 1
(dict-ref/default aed dict 1 #f) =&gt; #f</pre></blockquote>
-<h3 id="mutation">Mutation</h3>
-<p>All these procedures exist in pairs, with and without a final <code>!</code>. The ones without <code>!</code> are functional: they never side-effect their arguments, but may copy them. The ones with <code>!</code> are linear-update: they may return either a new dictionary object (which may or may not share storage with the <em>dictionary</em> argument), or the same dictionary object, mutated. In either case it is an error to access the dictionary later through any other reference to it, as that reference may have been invalidated. These procedures are defined as linear-update because the underlying type-specific operations may be functional, mutational, or themselves linear-update.</p>
+<h3 id="mutation">Functional update and mutation</h3>
+<p>All these procedures exist in pairs, with and without a final <code>!</code>. The ones without <code>!</code> are functional: they never side-effect their arguments, but the result may share structure with the <em>dict</em> argument. The ones with <code>!</code> are mutations: they they change the <em>dict</em> argument. However, only one set of procedures is supported in any dictionary: for example, SRFI 125 hash tables support only mutation, whereas SRFI 146 mappings support only functional update. The <code>dict-mutable?</code> procedure can be used to determine which set is usable.</p>
<p><code>(dict-set</code>&nbsp;<em>dtd dictionary obj</em> …<code>)</code><br>
<code>(dict-set!</code>&nbsp;<em>dtd dictionary obj</em> …<code>)</code></p>
<p>Returns a dictionary that contains all the associations of <em>dictionary</em> plus those specified by <em>objs</em>, which alternate between keys and values. If a key to be added already exists in <em>dictionary</em>, the new value prevails.</p>
@@ -165,22 +151,11 @@ Otherwise, returns two values, a dictionary that contains all the associations o
((3 . 4) (5 . 6))
1
2</pre></blockquote>
-<p><code>(dict-map</code>&nbsp;<em>dtd proc dictionary</em><code>)</code><br>
-<code>(dict-map!</code>&nbsp;<em>dtd proc dictionary</em><code>)</code></p>
-<p>Returns a dictionary similar to <em>dictionary</em> that maps each key of <em>dictionary</em> to the value that results from invoking <em>proc</em> on the corresponding key and value of <em>dictionary</em>.</p>
-<blockquote><pre>(dict-map (lambda (k v) (cons v k)) aed dict) =&gt; ((2 . 1) (4 . 3) (6 . 5))</pre></blockquote>
-<blockquote><pre>(dict-map! (lambda (k v) (cons v k)) aed dict) =&gt; ((2 . 1) (4 . 3) (6 . 5))</pre></blockquote>
-<p><code>(dict-filter</code>&nbsp;<em>dtd pred dictionary</em><code>)</code><br>
-<code>(dict-filter!</code>&nbsp;<em>dtd pred dictionary</em><code>)</code><br>
-<code>(dict-remove</code>&nbsp;<em>dtd pred dictionary</em><code>)</code><br>
-<code>(dict-remove!</code>&nbsp;<em>dtd pred dictionary</em><code>)</code></p>
-<p>Returns a dictionary similar to <em>dictionary</em> that contains just the associations of <em>dictionary</em> that satisfy / do not satisfy <em>pred</em> when it is invoked on the key and value of the association.</p>
-<blockquote><pre>(dict-filter (lambda (k v) (= k 1)) aed dict) =&gt; ((1 . 2))
-(dict-remove (lambda (k) (= k 1)) aed dict) =&gt; ((3 . 4) (5 . 6))</pre></blockquote>
-<p><code>(dict-search</code>&nbsp;<em>dtd dictionary key failure success</em><code>)</code><br>
-<code>(dict-search!</code>&nbsp;<em>dtd dictionary key failure success</em><code>)</code></p>
-<p>This procedure is a workhorse for dictionary lookup, insert, and delete. The dictionary <em>dictionary</em> is searched for an association whose key is the same as <em>key</em> in the sense of <em>dictionary</em>. If one is not found, then the <em>failure</em> procedure is tail-called with two procedure arguments, <em>insert</em> and <em>ignore</em>, and is expected to tail-call one of them.</p>
-<p>However, if such an association is found, then the <em>success</em> procedure is tail-called with the matching key of <em>dictionary</em>, the associated value, and two procedure arguments, <em>update</em> and <em>remove</em>, and is expected to tail-call one of them.</p>
+<p><code>(dict-alter</code>&nbsp;<em>dtd dictionary key failure success</em><code>)</code><br>
+<code>(dict-alter!</code>&nbsp;<em>dtd dictionary key failure success</em><code>)</code></p>
+<p>This procedure is a workhorse for dictionary lookup, insert, and delete. The dictionary <em>dictionary</em> is searched for an association whose key is the same as <em>key</em>. If one is not found, then the <em>failure</em> procedure is tail-called with two procedure arguments, <em>insert</em> and <em>ignore</em>.</p>
+<p>In either case, the values returned by <em>failure</em> or <em>success</em> are returned.</p>
+<p>If such an association is found, then the <em>success</em> procedure is tail-called with the matching key of <em>dictionary</em>, the associated value, and two procedure arguments, <em>update</em> and <em>remove</em>.</p>
<p>It is an error if the procedure arguments are invoked other than in tail position in the <em>failure</em> and <em>success</em> procedures. It is also an error if the <em>failure</em> and <em>success</em> procedures return to their implicit continuation without invoking one of their arguments.</p>
<p>The behaviors of the procedures are as follows (where <em>obj</em> is any Scheme object):</p>
<ul>
@@ -190,13 +165,13 @@ Otherwise, returns two values, a dictionary that contains all the associations o
<li><p>Invoking <code>(</code><em>remove obj</em><code>)</code> returns a dictionary that contains all the associations of <em>dictionary</em>, except for the association with key key.</p></li>
</ul>
<p>In all cases, <em>obj</em> is returned as a second value.</p>
-<p>Here are four examples of <code>dict-search</code>,
+<p>Here are four examples of <code>dict-alter</code>,
one for each of the four procedures:
<blockquote><pre>
;; ignore
(define-values
(dict value)
- (dict-search (alist->dict '((a . b))) 'c
+ (dict-alter (alist->dict '((a . b))) 'c
(lambda (insert ignore)
(ignore 'foo))
(lambda args
@@ -207,7 +182,7 @@ one for each of the four procedures:
;; insert
(define-values
(dict value)
- (dict-search (alist->dict '((a . b))) 'c
+ (dict-alter (alist->dict '((a . b))) 'c
(lambda (insert ignore)
(insert 'd 'foo))
(lambda args
@@ -219,7 +194,7 @@ one for each of the four procedures:
;; update
(define-values
(dict value)
- (dict-search (alist->dict '((a . b))) 'a
+ (dict-alter (alist->dict '((a . b))) 'a
(lambda args
(error))
(lambda (key value update delete)
@@ -230,7 +205,7 @@ one for each of the four procedures:
;; delete
(define-values
(dict value)
- (dict-search (alist->dict '((a . b) (c . d))) 'a
+ (dict-alter (alist->dict '((a . b) (c . d))) 'a
(lambda args
(error))
(lambda (key value update delete)
@@ -239,16 +214,9 @@ one for each of the four procedures:
value => foo
</pre></blockquote>
<h3 id="the-whole-dictionary">The whole dictionary</h3>
-<p><code>(dict-copy</code>&nbsp;<em>dtd dictionary</em><code>)</code><p>
-Returns a dictionary that is similar to <em>dictionary</em> and contains the same associations. Mutating the result of <code>dict-copy</code> does not affect <em>dictionary</em> or vice versa.</p>
<p><code>(dict-size</code>&nbsp;<em>dtd dictionary</em><code>)</code></p>
<p>Returns an exact integer representing the number of associations in <em>dictionary</em>.</p>
<blockquote><pre>(dict-size aed dict) =&gt; 3</pre></blockquote>
-<p><code>(dict-for-each</code>&nbsp;<em>dtd proc dictionary</em><code>)</code></p>
-<p>Invokes <em>proc</em> on each key of <em>dictionary</em> and its corresponding value in that order. This procedure is used for doing operations on the whole dictionary. If the dictionary type is inherently ordered, associations are processed in the inherent order; otherwise in an arbitrary order. Returns an unspecified value.</p>
-<blockquote><pre>(define (write-key key value) (write key))
-(dict-for-each write-key aed dict) =&gt; unspecified
- ; writes &quot;135&quot; to current output</pre></blockquote>
<p><code>(dict-count</code>&nbsp;<em>dtd pred dictionary</em><code>)</code></p>
<p>Passes each association of dictionary as two arguments to <em>pred</em> and returns the number of times that <em>pred</em> returned true as an an exact integer.</p>
<blockquote><pre>(dict-count aed dict (lambda (k v) (even? k))) =&gt; 0</pre></blockquote>
@@ -288,21 +256,37 @@ Returns a dictionary that is similar to <em>dictionary</em> and contains the sam
(dict-&gt;alist &#39;(1 2 3 4 5 6)) =&gt; ((1 . 2) (3 . 4) (5 . 6))</pre></blockquote>
<p>Add <code>dict-map</code>,
<code>dict-filter</code>, <code>dict-remove</code>,
-and <code>dict-search</code>.
+and <code>dict-alter</code>.
</p>
<p><code>(dict-comparator</code>&nbsp;<em>dtd dictionary</em><code>)</code></p>
<p>Return a comparator representing the type predicate, equality predicate, ordering predicate, and hash function of <em>dict</em>. The last two may be <code>#f</code> if the dictionary does not make use of these functions.</p>
-<p>If no comparator is relative to the dictionary type, returns <code>#f</code>.</p>
-<h3 id="dictionary-type-descriptors">Dictionary type descriptors</h3>
+<p>If no comparator is relevant to the dictionary type, returns <code>#f</code>.</p>
+<h3 id="iteration">Iteration</h3>
+<p><code>(dict-for-each</code>&nbsp;<em>dtd proc dictionary</em><code>)</code></p>
+<p>Invokes <em>proc</em> on each key of <em>dictionary</em> and its corresponding value in that order. This procedure is used for doing operations on the whole dictionary. If the dictionary type is inherently ordered, associations are processed in the inherent order; otherwise in an arbitrary order. Returns an unspecified value.</p>
+<blockquote><pre>(define (write-key key value) (write key))
+(dict-for-each write-key aed dict) =&gt; unspecified
+ ; writes &quot;135&quot; to current output</pre></blockquote>
+<p><code>(dict-for-each&lt;</code>&nbsp;<em>dtd proc dictionary key</em><code>)</code></p>
+<p><code>(dict-for-each&lt;=</code>&nbsp;<em>dtd proc dictionary key</em><code>)</code></p>
+<p><code>(dict-for-each&gt;</code>&nbsp;<em>dtd proc dictionary key</em><code>)</code></p>
+<p><code>(dict-for-each&gt;=</code>&nbsp;<em>dtd proc dictionary key</em><code>)</code></p>
+<p>Invokes <em>proc</em> on each key of <em>dictionary</em> that is less than / less than or equal to / greater than / greater than or equal to <em>key</em> and its corresponding value. This procedure is used for doing operations on part of the dictionary. If the dictionary type is inherently ordered, associations are processed in the inherent order; otherwise in an arbitrary order. Returns an unspecified value.</p>
+<p><code>(dict-for-each-in-open-interval</code>&nbsp;<em>dtd proc dictionary key1 key2</em><code>)</code></p>
+<p><code>(dict-for-each-in-closed-interval</code>&nbsp;<em>dtd proc dictionary key1 key2</em><code>)</code></p>
+<p><code>(dict-for-each-in-open-closed-interval</code>&nbsp;<em>dtd proc dictionary key1 key2</em><code>)</code></p>
+<p><code>(dict-for-each-in-closed-open-interval</code>&nbsp;<em>dtd proc dictionary key1 key2</em><code>)</code></p>
+<p>Invokes <em>proc</em> on each key of <em>dictionary</em> that is that is within the specified interval between <em>key1</em> and <em>key2</em>, and its corresponding value. This procedure is used for doing operations on part of the dictionary. If the dictionary type is inherently ordered, associations are processed in the inherent order; otherwise in an arbitrary order. Returns an unspecified value.</p>
+<h3 id="dictionary-type-descriptor-procedures">Dictionary type descriptor procedures</h3>
<p><code>(dtd?</code>&nbsp;<em>obj</em><code>)</code></p>
<p>Returns <code>#t</code> if <em>obj</em> is a DTD, and <code>#f</code> otherwise.</p>
-<p><code>(make-dtd</code>&nbsp;<em>arg</em> …<code>)</code><br>
-<code>(dtd</code>&nbsp;(<em>proc-id proc</em>) …<code>)</code>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[syntax]</p>
-<p>Returns a new dictionary type providing procedures that allow manipulation of dictionaries of that type. The <em>args</em> are alternately <em>proc-ids</em> and corresponding <em>procs</em>.</p>
-<p>A <em>proc-id</em> argument is the value of a variable whose name is the same as a procedure (except those in this section and the Exceptions section) suffixed with <code>-id</code>, and a <em>proc</em> argument is the specific procedure implementing it for this type. These procedures only need to handle a full-length argument list (except when defining <code>dict-ref</code> and <code>dict-update!</code>), as the other defaults have already been supplied by the framework.</p>
+<p><code>(make-dtd</code>&nbsp;<em>comparator mutable arg</em> …<code>)</code><br>
+<code>(dtd</code>&nbsp;<em>comparator mutable </em>(<em>proc-id proc</em>) …<code>)</code>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;[syntax]</p>
+<p>Returns a new dictionary type providing procedures that allow manipulation of dictionaries of that type The <em>comparator</em> argument specifies the comparator of the underlying dictionary; the <em>mutable</em> argument is <code>#t</code> if the underlying dictionary is mutable and <code>#f</code> if not. The <em>args</em> are alternately <em>proc-ids</em> and corresponding <em>procs</em>.</p>
+<p>A <em>proc-id</em> argument is the value of a variable whose name is the same as a procedure (except those in this section and the Exceptions section) suffixed with <code>-id</code>, and a <em>proc</em> argument is the specific procedure implementing it for this type. Note that there is only one proc-id for functional updaters and corresponding mutators. These procedures only need to handle a full-length argument list (except when defining <code>dict-ref</code> and <code>dict-update!</code>), as the other defaults have already been supplied by the framework.</p>
<p><b>FIXME: Is the parenthesized part still true?</b></p>
<p>
-Arguments for the six procedures <code>make-dictionary</code>, <code>dictionary?</code>, <code>dict-size</code>, <code>dict-search</code>, <code>dict-search!</code>, and <code>dict-for-each</code> are needed to make a fully functional DTD, but it is not an error to omit them. The others are optional, but if provided can be more efficient than the versions automatically provided by the implementation of this SRFI.</p>
+Arguments for the five procedures <code>dictionary?</code>, <code>dict-size</code>, <code>dict-alter</code>, <code>dict-alter!</code>, and <code>dict-for-each</code> are needed to make a fully functional DTD, but it is not an error to omit them. The others are optional, but if provided can be more efficient than the versions automatically provided by the implementation of this SRFI.</p>
<p>The <code>dtd</code> macro behaves like a wrapper around <code>make-dtd</code>, but may also verify that the <em>proc-ids</em> are valid, that there are no duplicates, etc.</p>
<p>The following examples are from the file <code>plist-impl.scm</code>
in the sample implementation; the procedures referred to are also in
@@ -311,8 +295,7 @@ that file.<p>
(make-dtd
make-dictionary-id (lambda (comparator) '())
dictionary?-id plist?
- dict-search-id plist-search
- dict-search!-id plist-search!
+ dict-alter-id plist-alter
dict-size-id plist-size
dict-for-each-id plist-foreach
dict->alist-id plist->alist)) =&gt; a DTD for plists
@@ -320,8 +303,7 @@ that file.<p>
(dtd
(make-dictionary-id (lambda (comparator) '()))
(dictionary?-id plist?)
- (dict-search-id plist-search)
- (dict-search!-id plist-search!)
+ (dict-alter-id plist-alter)
(dict-size-id plist-size)
(dict-for-each-id plist-foreach)
(dict->alist-id plist->alist)) =&gt; a DTD for plists
@@ -375,37 +357,22 @@ and <code>#f</code> otherwise.
<code>dictionary?-id</code>,
<code>dict-empty?-id</code>,
<code>dict-contains?-id</code>,
+<code>dict-mutable?-id</code>,
<code>dict-ref-id</code>,
<code>dict-ref/default-id</code>,
<code>dict-set-id</code>,
<code>dict-adjoin-id</code>,
-<code>dict-adjoin!-id</code>,
<code>dict-delete-id</code>,
-<code>dict-delete!-id</code>,
<code>dict-delete-all-id</code>,
-<code>dict-delete-all!-id</code>,
<code>dict-replace-id</code>,
-<code>dict-replace!-id</code>,
<code>dict-update-id</code>,
-<code>dict-update!-id</code>,
<code>dict-update/default-id</code>,
-<code>dict-update/default!-id</code>,
<code>dict-pop-id</code>,
-<code>dict-pop!-id</code>,
-<code>dict-map-id</code>,
-<code>dict-map!-id</code>,
-<code>dict-filter-id</code>,
-<code>dict-filter!-id</code>,
-<code>dict-remove-id</code>,
-<code>dict-remove!-id</code>,
-<code>dict-search-id</code>,
-<code>dict-search!-id</code>,
-<code>dict-copy-id</code>,
+<code>dict-alter-id</code>,
<code>dict-size-id</code>,
<code>dict-count-id</code>,
<code>dict-any-id</code>,
<code>dict-every-id</code>,
-<code>dict-keys-id</code>,
<code>dict-values-id</code>,
<code>dict-entries-id</code>,
<code>dict-fold-id</code>,
@@ -427,15 +394,15 @@ new dictionary types that may not have complete dictionary APIs:</p>
<ul>
<li><code>dict-empty?</code> depends on <code>dict-size</code></li>
<li><code>dict-contains?</code> depends on <code>dict-ref</code></li>
-<li><code>dict-ref</code> depends on <code>dict-search!</code></li>
+<li><code>dict-ref</code> depends on <code>dict-alter!</code></li>
<li><code>dict-ref/default</code> depends on <code>dict-ref</code></li>
-<li><code>dict-set!</code> depends on <code>dict-search!</code></li>
-<li><code>dict-adjoin!</code> depends on <code>dict-search!</code></li>
+<li><code>dict-set!</code> depends on <code>dict-alter!</code></li>
+<li><code>dict-adjoin!</code> depends on <code>dict-alter!</code></li>
<li><code>dict-delete!</code> depends on <code>dict-delete-all!</code></li>
-<li><code>dict-delete-all!</code> depends on <code>dict-search!</code></li>
-<li><code>dict-replace!</code> depends on <code>dict-search!</code></li>
-<li><code>dict-intern!</code> depends on <code>dict-search!</code></li>
-<li><code>dict-update!</code> depends on <code>dict-search!</code></li>
+<li><code>dict-delete-all!</code> depends on <code>dict-alter!</code></li>
+<li><code>dict-replace!</code> depends on <code>dict-alter!</code></li>
+<li><code>dict-intern!</code> depends on <code>dict-alter!</code></li>
+<li><code>dict-update!</code> depends on <code>dict-alter!</code></li>
<li><code>dict-update/default!</code> depends on <code>dict-update!</code></li>
<li><code>dict-pop!</code> depends on <code>dict-for-each</code>, <code>dict-delete!</code>, <code>dict-empty?</code></li>
<li><code>dict-remove!</code> depends on <code>dict-filter!</code></li>