rewrite [Pattern]

Enumerates items based on user specified rewrite rules. Each item is represented by a node in the pattern. Rewrite rules are expressed in terms of node identifiers. Two different styles of rule specification are allowed.

The first method associates a rewrite expression with each node in the pattern. This method is capable of describing many sorts of context-free morphologies. The form of this node specification is similar to the graph pattern:

({item} {option value}+)

item is the item to return from the node. Following item come zero or more options value pairs:

id {datum}
Sets datum to be the unique identifier for the node in the pattern. The identifier may be any Lisp object as long as its uniquely represented in the pattern. If omitted, the identifier defaults to element. It is good practice to provide each node with an explicit id.
to {id | (id+) | stream | nil}
Sets the rewrite expression for the node. The value may be a single id, a list of ids, an item stream or nil. If the value is nil the node is terminal, i.e. produces no successor(s) in the next generation. If the value is an item stream then the stream is read to produce a successor term each time the node is rewritten. Otherwise the value should be the id or list of ids that name the successor node(s) in the next generation.
The second style of rule specification permits context-sensitive rules (rules involving more than one node in their left hand side) to be defined. In this method a list of rules is associated with the entire pattern rather than with nodes in the pattern. There may be more or fewer rules than there are nodes. The rule list is interpreted as an ordered set. To produce a new generation, each node in the current generation is matched against the rule list to find the successor rule to apply to the node. The first rule that matches is applied and the id(s) in the right-hand side of the rule produce the successor node(s) in the next generation. Node specification for the second method is similar to the first, except that the to option is ignored and if the id of the node is the same as its element then the node does not need to be specified as a list. Each rule is a list of the form:

({id}+ -> {id}*)

The -> operator divides each rule into two parts. The left-hand side of the rule defines the "matching target" and the right-hand side defines the rewrite succession. Either or both sides may contain more than one id. If the left-hand side of the rule is a single id then the rule matches any node with the same id. If the left-hand side has more than one id (a context-sensitive rule) then the rule matches if the "strict predecessor" in the left-hand side matches the current node and the nodes around the current node in the generation match the ids around the strict predecessor in the left-hand side. The strict predecessor id is marked by a list. Every context rule must contain exactly one strict predecessor in its left hand side. Here are three examples of context rules: (1 (1) 2 -> 3) means node 1 rewrites to node 3 whenever 1 is preceded by itself and followed by 2 in the current generation. (1 * (2) -> 1 2) means node 2 rewrites to 1 and 2 whenever 1 occurs two positions earlier in the current generation. (5 (3) 3 4 -> ) means node 3 rewrites to nothing if preceded by 5 and followed by itself and 4 in the current generation. Note that the right-hand side may be empty and that the left-hand side may contain the wild card * which matches any single element in the current generation.

rewrite implements the following option value pairs:

rules {list}
Sets the rewrite rule list for the pattern to list.
initially {id | list}
Sets the initial generation of the pattern to the specified id(s). Defaults to the first node in the pattern if not specified.
generations {integer}
Sets the number of generations to compute. Generations are counted from 1, while this count is less than integer the pattern performs rewriting. Generations later than integer reuse the last rewritten generation, as if the stream were implemented as a cyclic.

Example:

;;; rule specification method 1

? (setf x (items (1 to 2) (2 to 3) (3 to (3 1)) in rewrite))
#<REWRITE-ITEM-STREAM 132273601>

? (read-items x 20)
(1 2 3 3 1 3 1 2 3 1 2 3 3 1 2 3 3 1 3 1)

;;; rule specification method 2

? (setf x (notes a b c d in rewrite
                 rules '((a -> a b) (a b (b) c -> d)
                         (b -> b c) (c -> c a))))
#<REWRITE-NOTE-STREAM 132114101>

? (read-items x 30)
(A4 A4 B4 A4 B4 B4 C4 A4 B4 B4 C4 D4 C4 A4 A4 B4 B4 C4 D4 C4
  A4 C4 A4 A4 B4 A4 B4 B4 C4 D4)

See Also:

Item Streams


Last Modified: 5-Mar-1998