Initial import of Arboretuum version 1.0 revision 2008.0304 sources.
Cat's Eye Technologies
12 years ago
0 | <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/2002/REC-xhtml1-20020801/DTD/xhtml1-strict.dtd"> | |
1 | <html xmlns="http://www.w3.org/1999/xhtml" lang="en"> | |
2 | <head> | |
3 | <title>The Arboretuum Programming Language</title> | |
4 | </head> | |
5 | <body> | |
6 | ||
7 | <h1>The Arboretuum Programming Language</h1> | |
8 | ||
9 | <p>March 2008, Chris Pressey, Cat's Eye Technologies.</p> | |
10 | ||
11 | <h2>Description</h2> | |
12 | ||
13 | <p><dfn>Arboretuum</dfn> is a language based on an experimental variant of | |
14 | tree-rewriting which we call <dfn>forest-rewriting</dfn>. Appropriate to its name, during | |
15 | forest-rewriting, multiple trees (specifically, a finite set) are rewritten. | |
16 | Each tree is labelled with a name; a rewriting pattern can refer to multiple trees, | |
17 | and must match all of them simultaneously in order for a replacement to occur.</p> | |
18 | ||
19 | <p>As an experiment, Arboretuum was not entirely a success. Forest-rewriting unfortunately turned out to | |
20 | be insufficient for what I wanted to apply it to, namely compiler specification. The idea | |
21 | was to have each tree associated with some data structure used in the compilation process | |
22 | (AST, symbol table, output buffer, etc.) However, it became apparent that, by itself, | |
23 | forest-rewriting could not synchronize the data across the trees the way it would need | |
24 | to be synchronized in a real compiler. I plan to tackle the problem again, with a different variation | |
25 | on rewriting, in a future project.</p> | |
26 | ||
27 | <p>Regardless, Arboretuum is Turing-complete, as tree-rewriting is simply a special | |
28 | case of forest-rewriting: just have one tree in the forest.</p> | |
29 | ||
30 | <h2>Implementation</h2> | |
31 | ||
32 | <p>I will refer you to the reference implementation of Arboretuum | |
33 | for details on the semantics of the language. Ordinarily I frown upon this | |
34 | sort of practice -- normatively defining a language by an implementation | |
35 | rather than by a specification -- but the interests of brevity, the experimental tack of the | |
36 | project, the unsuccessful outcome of the experiment, and the relative | |
37 | well-definedness of the implementation language (the purely functional subset of R<sup>5</sup>RS Scheme) conspire | |
38 | to make the consequences of this choice less painful than usual.</p> | |
39 | ||
40 | <p>The reference implementation comprises the following files:</p> | |
41 | ||
42 | <ul> | |
43 | ||
44 | <li><code>preprocess.scm</code> | |
45 | <p>Pre-processes the input program into an internal format | |
46 | suitable for forest-rewriting. | |
47 | </p></li> | |
48 | ||
49 | <li><code>unify.scm</code> | |
50 | <p>Implementation of the unification algorithm which is used to match | |
51 | the pattern part of rewriting rules to the forest. | |
52 | </p></li> | |
53 | ||
54 | <li><code>forest-rewrite.scm</code> | |
55 | <p>Implements the forest-rewriting process proper. | |
56 | </p></li> | |
57 | ||
58 | <li><code>utils.scm</code> | |
59 | <p>Miscellanous support procedures, including <code>mergesort</code>, | |
60 | <code>vector-store</code> (a side-effect-free alternative to <code>vector-set!</code>), | |
61 | <code>print</code> and <code>test</code>. | |
62 | </p></li> | |
63 | ||
64 | </ul> | |
65 | ||
66 | <p>In addition, the following supplementary files which are not definitive | |
67 | w.r.t. the Arboretuum language are included in the project:</p> | |
68 | ||
69 | <ul> | |
70 | ||
71 | <li><code>tests.scm</code> | |
72 | <p>Gives a set of unit tests to confirm the absence of certain erroneous behaviours. | |
73 | (Obviously, no number of unit tests could confirm the absence of <em>errors</em>...) | |
74 | </p></li> | |
75 | ||
76 | <li><code>tree-rewrite.scm</code> | |
77 | <p>Some basic tree-rewriting code, to provide contrast between it's complexity | |
78 | and that of forest rewriting.</p> | |
79 | ||
80 | </p></li> | |
81 | ||
82 | </ul> | |
83 | ||
84 | <p>Note that the Scheme implementation of algorithms in the above files are | |
85 | to be taken as <em>pedantic</em> rather than <em>efficient</em>. | |
86 | They are meant to be read (perhaps even enjoyed?) and only incidentally | |
87 | to be executed.</p> | |
88 | ||
89 | <h2>History</h2> | |
90 | ||
91 | <p>This project was begun in January 2006. I'd been meaning to release | |
92 | it for a while before actually doing so in March of 2008.</p> | |
93 | ||
94 | <p>Happy forest-rewriting!</p> | |
95 | ||
96 | <p>-Chris Pressey | |
97 | <br>Cat's Eye Technologies | |
98 | <br>March 4, 2008 | |
99 | <br>Chicago, Illinois, USA</p> | |
100 | ||
101 | ||
102 | </body> | |
103 | </html> |
0 | ; | |
1 | ; Forest Rewriting | |
2 | ; Chris Pressey, late January 2006 | |
3 | ; | |
4 | ||
5 | ; Copyright (c)2008 Cat's Eye Technologies. All rights reserved. | |
6 | ; | |
7 | ; Redistribution and use in source and binary forms, with or without | |
8 | ; modification, are permitted provided that the following conditions | |
9 | ; are met: | |
10 | ; | |
11 | ; 1. Redistributions of source code must retain the above copyright | |
12 | ; notices, this list of conditions and the following disclaimer. | |
13 | ; 2. Redistributions in binary form must reproduce the above copyright | |
14 | ; notices, this list of conditions, and the following disclaimer in | |
15 | ; the documentation and/or other materials provided with the | |
16 | ; distribution. | |
17 | ; 3. Neither the names of the copyright holders nor the names of their | |
18 | ; contributors may be used to endorse or promote products derived | |
19 | ; from this software without specific prior written permission. | |
20 | ; | |
21 | ; THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
22 | ; ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES INCLUDING, BUT NOT | |
23 | ; LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS | |
24 | ; FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE | |
25 | ; COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, | |
26 | ; INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, | |
27 | ; BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | |
28 | ; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER | |
29 | ; CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
30 | ; LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN | |
31 | ; ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | |
32 | ; POSSIBILITY OF SUCH DAMAGE. | |
33 | ||
34 | ; | |
35 | ; Given a term, a pattern to look for in that term, a replacement pattern, | |
36 | ; and a unifier (set of substitutions,) determine if the term could be | |
37 | ; rewritten, and if so, return a vector consisting of: | |
38 | ; | |
39 | ; - a partially rewritten term. The replacement pattern is substituted into | |
40 | ; the term but WITHOUT the variables expanded into ground terms. | |
41 | ; - a (possibly new) unifier | |
42 | ; | |
43 | ; The rewrite process first recurses into the term's children (bottom-up | |
44 | ; rewriting.) If the given pattern fails to unify anywhere in the term, | |
45 | ; #f is returned. | |
46 | ; | |
47 | (define partial-rewrite | |
48 | (lambda (term pattern replacement unifier) | |
49 | (cond ((list? term) | |
50 | (let loop ((subterms term) ; first try to unify with each child | |
51 | (acc '())) ; keep track of subterms we've seen | |
52 | (cond ((null? subterms) ; no more children. lament failure. | |
53 | (direct-partial-rewrite term pattern replacement unifier)) | |
54 | (else | |
55 | (let* ((subterm (car subterms)) | |
56 | (rest (cdr subterms)) | |
57 | (result (partial-rewrite subterm pattern replacement unifier))) | |
58 | (cond (result ; this child succeeded. pass along its result | |
59 | (let* ((result-term (vector-ref result 0)) | |
60 | (result-unifier (vector-ref result 1)) | |
61 | (front (reverse acc)) | |
62 | (back (cons result-term rest)) | |
63 | (spliced-term (append front back))) | |
64 | (vector spliced-term result-unifier))) | |
65 | (else ; this child failed, | |
66 | (loop rest (cons subterm acc))))))))) ; try the next one. | |
67 | (else | |
68 | (direct-partial-rewrite term pattern replacement unifier))))) | |
69 | ||
70 | ; | |
71 | ; Essentially a helper function for partial-rewrite; if the given | |
72 | ; pattern unifies with the given term, just return a vector containing | |
73 | ; the replacement and the (updated) unifier, else return #f. | |
74 | ; | |
75 | (define direct-partial-rewrite | |
76 | (lambda (term pattern replacement unifier) | |
77 | (let* ((new-unifier (unify term pattern unifier))) ; try to unify | |
78 | (cond (new-unifier ; successfully unified, so rewrite | |
79 | (vector replacement new-unifier)) | |
80 | (else | |
81 | #f))))) | |
82 | ||
83 | ; | |
84 | ; Given a vector of terms with variable placeholders in them, and | |
85 | ; a unifier, modify the vector so that the variables are replaced | |
86 | ; by their respective replacements (substitutions) in the unifier, | |
87 | ; and return the modified vector. | |
88 | ; | |
89 | (define expand-forest | |
90 | (lambda (terms unifier) | |
91 | (let loop ((terms terms) | |
92 | (term-num (- (vector-length terms) 1))) | |
93 | (cond ((< term-num 0) | |
94 | terms) | |
95 | (else | |
96 | (let* ((term (vector-ref terms term-num)) | |
97 | (new-term (expand-vars term unifier)) | |
98 | (new-terms (vector-store terms term-num new-term)) | |
99 | (next-term-num (- term-num 1))) | |
100 | (loop new-terms next-term-num))))))) | |
101 | ||
102 | ; | |
103 | ; Rewrite a vector of terms in tandem using a list of rules, with a | |
104 | ; shared unifier (so that variable matches are common to all terms.) | |
105 | ; Return a vector of rewritten terms, if the rule list matched, otherwise #f. | |
106 | ; | |
107 | (define rewrite-terms-with-compound-rule | |
108 | (lambda (original-terms original-compound-rule) | |
109 | (let loop ((terms original-terms) | |
110 | (compound-rule original-compound-rule) | |
111 | (unifier '())) | |
112 | (cond ((null? compound-rule) ; when we reach the end of the list, | |
113 | (expand-forest terms unifier)) ; expand variables in all the new terms | |
114 | (else | |
115 | (let* ((rule (car compound-rule)) | |
116 | (rest-rules (cdr compound-rule)) | |
117 | (targ-term-no (vector-ref rule 0)) | |
118 | (pattern (vector-ref rule 1)) | |
119 | (replacement (vector-ref rule 2)) | |
120 | (term (vector-ref terms targ-term-no)) | |
121 | (result (partial-rewrite term pattern replacement unifier))) | |
122 | (cond (result ; we matched. update term, and try the next rule | |
123 | (let* ((new-term (vector-ref result 0)) | |
124 | (new-unifier (vector-ref result 1)) | |
125 | (new-terms (vector-store terms targ-term-no new-term))) | |
126 | (loop new-terms rest-rules new-unifier))) | |
127 | (else ; no match. abort the entire thing. | |
128 | #f)))))))) | |
129 | ||
130 | ; | |
131 | ; Given a vector(#2) of: | |
132 | ; a vector of terms, and | |
133 | ; a list of compound rules, | |
134 | ; rewrite all terms simultaneously with each of the compound rules. | |
135 | ; Rewriting a set of terms simultaneously means that the variables in the | |
136 | ; compound rule are shared across the terms, and will only unify with subterms | |
137 | ; that are common to all of the terms. | |
138 | ; | |
139 | ; Keep applying compound rules until there are none that apply any longer. | |
140 | ; | |
141 | ; Return a vector of terms so rewritten. | |
142 | ; | |
143 | (define rewrite-forest | |
144 | (lambda (everything) | |
145 | (let* ((original-terms (vector-ref everything 0)) | |
146 | (all-compound-rules (vector-ref everything 1))) | |
147 | (let loop ((terms original-terms) | |
148 | (compound-rules all-compound-rules)) | |
149 | (cond ((null? compound-rules) | |
150 | terms) ; terminate and return new termlist | |
151 | (else | |
152 | (let* ((compound-rule (car compound-rules)) | |
153 | (new-terms (rewrite-terms-with-compound-rule | |
154 | terms compound-rule))) | |
155 | (cond (new-terms ; successfully rewrote. | |
156 | (loop new-terms all-compound-rules)) ; try again, using all compound-rules | |
157 | (else | |
158 | (loop terms (cdr compound-rules))))))))))) ; try again, using rest of compound-rules |
0 | ; | |
1 | ; Preprocessor for Forest Rewriter | |
2 | ; Chris Pressey, sometime late January 2006 | |
3 | ; | |
4 | ||
5 | ; Copyright (c)2008 Cat's Eye Technologies. All rights reserved. | |
6 | ; | |
7 | ; Redistribution and use in source and binary forms, with or without | |
8 | ; modification, are permitted provided that the following conditions | |
9 | ; are met: | |
10 | ; | |
11 | ; 1. Redistributions of source code must retain the above copyright | |
12 | ; notices, this list of conditions and the following disclaimer. | |
13 | ; 2. Redistributions in binary form must reproduce the above copyright | |
14 | ; notices, this list of conditions, and the following disclaimer in | |
15 | ; the documentation and/or other materials provided with the | |
16 | ; distribution. | |
17 | ; 3. Neither the names of the copyright holders nor the names of their | |
18 | ; contributors may be used to endorse or promote products derived | |
19 | ; from this software without specific prior written permission. | |
20 | ; | |
21 | ; THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
22 | ; ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES INCLUDING, BUT NOT | |
23 | ; LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS | |
24 | ; FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE | |
25 | ; COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, | |
26 | ; INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, | |
27 | ; BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | |
28 | ; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER | |
29 | ; CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
30 | ; LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN | |
31 | ; ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | |
32 | ; POSSIBILITY OF SUCH DAMAGE. | |
33 | ||
34 | ; | |
35 | ; The goal here is to allow the compound-rules to be specified in a nicer, | |
36 | ; more flexible syntax, and preprocess them so that they are in a form that | |
37 | ; this engine can handle (eventually they should be compiled to super-efficient | |
38 | ; sequential code that "knows" which rewrites are likely immediately after | |
39 | ; other rewrites occur; but, first things first.) | |
40 | ; | |
41 | ; The most important part of this is *sorting* the rules by *specificity* | |
42 | ; so that the most specific rules are applied first. | |
43 | ; | |
44 | ; Ideally this would solve all our problems. But it might not, so we probably | |
45 | ; want a stable sorting algorithm that preserves the relative order specified | |
46 | ; by the programmer. | |
47 | ; | |
48 | ; Another reason to do this is to do type checking and other static analysis. | |
49 | ; e.g. a variable which appears on some RHS of a compound-rule, must also | |
50 | ; appear on some LHS of that compound-rule. | |
51 | ; | |
52 | ||
53 | ; | |
54 | ; The terms and compound-rules, before preprocessing, look like this: | |
55 | ; | |
56 | ; ( | |
57 | ; ( ; list of named terms | |
58 | ; (ast: ()) ; a named terms | |
59 | ; (stab: ()) | |
60 | ; (out: ()) | |
61 | ; ) | |
62 | ; ( ; list of compound-rules | |
63 | ; ((ast: foo => bar) (stab: bee => hive)) ; a compound-rule | |
64 | ; ) | |
65 | ; ) | |
66 | ||
67 | ||
68 | ; | |
69 | ; Let's borrow Aardappel's specificity ordering here: var < num < sym < list | |
70 | ; | |
71 | (define more-general-pattern-than? | |
72 | (lambda (pattern-a pattern-b) | |
73 | (cond ((null? pattern-a) | |
74 | #t) | |
75 | ((null? pattern-b) | |
76 | #f) | |
77 | ((and (list? pattern-a) (list? pattern-b)) | |
78 | (or (more-general-pattern-than? (car pattern-a) (car pattern-b)) | |
79 | (more-general-pattern-than? (cdr pattern-a) (cdr pattern-b)))) | |
80 | (else | |
81 | (< (term-specificity pattern-a) (term-specificity pattern-b)))))) | |
82 | ||
83 | (define term-specificity | |
84 | (lambda (term) | |
85 | (cond ((pattern-var? term) | |
86 | 1) | |
87 | ((number? term) | |
88 | 2) | |
89 | ((symbol? term) | |
90 | 3) | |
91 | (else ; list, most likely | |
92 | 4)))) | |
93 | ||
94 | (define more-general-rule-than? | |
95 | (lambda (rule-a rule-b) | |
96 | (let* ((pattern-a (vector-ref rule-a 1)) | |
97 | (pattern-b (vector-ref rule-b 1))) | |
98 | (more-general-pattern-than? pattern-a pattern-b)))) | |
99 | ||
100 | (define sort-compound-rule | |
101 | (lambda (compound-rule) | |
102 | (mergesort compound-rule more-general-rule-than?))) | |
103 | ||
104 | ; | |
105 | ; Returns a list like: ((ast: . 1) (stab: . 2) (out: . 3)) | |
106 | ; so that we can access a term's position in the vector given its name | |
107 | ; | |
108 | (define form-term-map | |
109 | (lambda (named-terms-depic n acc) | |
110 | (cond ((null? named-terms-depic) | |
111 | (reverse acc)) | |
112 | (else | |
113 | (let* ((named-term-depic (car named-terms-depic)) | |
114 | (name (car named-term-depic)) | |
115 | (pair (cons name n)) | |
116 | (new-acc (cons pair acc))) | |
117 | (form-term-map (cdr named-terms-depic) (+ n 1) new-acc)))))) | |
118 | ||
119 | (define preprocess-named-terms | |
120 | (lambda (named-terms-depic acc) | |
121 | (cond ((null? named-terms-depic) | |
122 | (list->vector (reverse acc))) | |
123 | (else | |
124 | (let* ((named-term-depic (car named-terms-depic)) | |
125 | (term (cadr named-term-depic)) | |
126 | (new-acc (cons term acc))) | |
127 | (preprocess-named-terms (cdr named-terms-depic) new-acc)))))) | |
128 | ||
129 | ; | |
130 | ; ((ast: foo => bar) (stab: bee => hive)) | |
131 | ; | |
132 | (define preprocess-compound-rule | |
133 | (lambda (compound-rule-depic term-map acc) | |
134 | (cond ((null? compound-rule-depic) | |
135 | (reverse acc)) | |
136 | (else | |
137 | (let* ((rule-depic (car compound-rule-depic)) | |
138 | (rule-term-name (car rule-depic)) | |
139 | (rule-term-index (cdr (assq rule-term-name term-map))) | |
140 | (rule-pattern (cadr rule-depic)) | |
141 | (rule-replacement (cadddr rule-depic)) | |
142 | (rule (vector rule-term-index rule-pattern rule-replacement)) | |
143 | (new-acc (cons rule acc))) | |
144 | (preprocess-compound-rule (cdr compound-rule-depic) term-map new-acc)))))) | |
145 | ||
146 | (define preprocess-compound-rules | |
147 | (lambda (compound-rules-depic term-map acc) | |
148 | (cond ((null? compound-rules-depic) | |
149 | (reverse acc)) | |
150 | (else | |
151 | (let* ((compound-rule-depic (car compound-rules-depic)) | |
152 | (compound-rule (preprocess-compound-rule compound-rule-depic term-map '())) | |
153 | (sorted-compound-rule (sort-compound-rule compound-rule)) | |
154 | (new-acc (cons sorted-compound-rule acc))) | |
155 | (preprocess-compound-rules (cdr compound-rules-depic) term-map new-acc)))))) | |
156 | ||
157 | (define preprocess | |
158 | (lambda (depic) | |
159 | (let* ((named-terms-depic (car depic)) | |
160 | (compound-rules-depic (cadr depic)) | |
161 | (term-map (form-term-map named-terms-depic 0 '())) | |
162 | (term-vector (preprocess-named-terms named-terms-depic '())) | |
163 | (compound-rules (preprocess-compound-rules compound-rules-depic term-map '()))) | |
164 | (vector term-vector compound-rules)))) |
0 | ; | |
1 | ; Test suite for forest-rewriting project | |
2 | ; Chris Pressey, sometime late January 2006 | |
3 | ; | |
4 | ||
5 | ; Copyright (c)2008 Cat's Eye Technologies. All rights reserved. | |
6 | ; | |
7 | ; Redistribution and use in source and binary forms, with or without | |
8 | ; modification, are permitted provided that the following conditions | |
9 | ; are met: | |
10 | ; | |
11 | ; 1. Redistributions of source code must retain the above copyright | |
12 | ; notices, this list of conditions and the following disclaimer. | |
13 | ; 2. Redistributions in binary form must reproduce the above copyright | |
14 | ; notices, this list of conditions, and the following disclaimer in | |
15 | ; the documentation and/or other materials provided with the | |
16 | ; distribution. | |
17 | ; 3. Neither the names of the copyright holders nor the names of their | |
18 | ; contributors may be used to endorse or promote products derived | |
19 | ; from this software without specific prior written permission. | |
20 | ; | |
21 | ; THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
22 | ; ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES INCLUDING, BUT NOT | |
23 | ; LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS | |
24 | ; FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE | |
25 | ; COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, | |
26 | ; INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, | |
27 | ; BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | |
28 | ; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER | |
29 | ; CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
30 | ; LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN | |
31 | ; ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | |
32 | ; POSSIBILITY OF SUCH DAMAGE. | |
33 | ||
34 | ||
35 | (load "utils.scm");-------------------------------------------------------- | |
36 | ||
37 | (test 'split-1 | |
38 | (lambda () | |
39 | (split '(1 2 3 4 5 6 7 8) '() '())) | |
40 | '((1 3 5 7) . (2 4 6 8)) | |
41 | ) | |
42 | ||
43 | (test 'split-2 | |
44 | (lambda () | |
45 | (split '(1 2 3 4 5 6 7) '() '())) | |
46 | '((1 3 5 7) . (2 4 6)) | |
47 | ) | |
48 | ||
49 | (test 'merge-1 | |
50 | (lambda () | |
51 | (merge '(2 4 6 8) '(1 3 5 7) > '())) | |
52 | '(1 2 3 4 5 6 7 8) | |
53 | ) | |
54 | ||
55 | (test 'split-and-merge-1 | |
56 | (lambda () | |
57 | (let* ((pair (split '(1 2 3 4 5 6 7) '() '())) | |
58 | (left (car pair)) | |
59 | (right (cdr pair))) | |
60 | (merge left right > '()))) | |
61 | '(1 2 3 4 5 6 7) | |
62 | ) | |
63 | ||
64 | (test 'mergesort-1 | |
65 | (lambda () | |
66 | (mergesort '(8 26 4 78 13 65 12 91 64 2) >)) | |
67 | '(2 4 8 12 13 26 64 65 78 91) | |
68 | ) | |
69 | ||
70 | (load "unify.scm");-------------------------------------------------------- | |
71 | ||
72 | (test 'unify-1 | |
73 | (lambda () | |
74 | (unify | |
75 | '(+ 1 2) | |
76 | '(+ #(a) #(b)) | |
77 | '() | |
78 | )) | |
79 | '((b . 2) (a . 1)) | |
80 | ) | |
81 | ||
82 | (test 'unify-2 | |
83 | (lambda () | |
84 | (unify | |
85 | '(+ 1 1) | |
86 | '(+ #(a) #(a)) | |
87 | '() | |
88 | )) | |
89 | '((a . 1)) | |
90 | ) | |
91 | ||
92 | (test 'unify-3 | |
93 | (lambda () | |
94 | (unify | |
95 | '(+ 1 2) | |
96 | '(+ #(a) #(a)) | |
97 | '() | |
98 | )) | |
99 | #f | |
100 | ) | |
101 | ||
102 | (test 'unify-4 | |
103 | (lambda () | |
104 | (unify | |
105 | '(+ 1 1) | |
106 | '(+ #(a) #(a)) | |
107 | '((a . 2)) | |
108 | )) | |
109 | #f | |
110 | ) | |
111 | ||
112 | (load "tree-rewrite.scm");-------------------------------------------------- | |
113 | ||
114 | (test 'reduce-term-1 | |
115 | (lambda () | |
116 | (reduce-term | |
117 | '(+ 6 (+ 3 3)) | |
118 | '( | |
119 | ((+ #(A) #(A)) . (* #(A) 2)) | |
120 | ) | |
121 | )) | |
122 | '(+ 6 (* 3 2)) | |
123 | ) | |
124 | ||
125 | (test 'reduce-term-2 | |
126 | (lambda () | |
127 | (reduce-term | |
128 | '(+ (const 9) (* (const 2) (const 3))) | |
129 | '( | |
130 | ((const #(a)) . (push #(a) _) ) | |
131 | ((+ #(l) #(r)) . (then (then #(l) #(r)) (add _)) ) | |
132 | ((* #(l) #(r)) . (then (then #(l) #(r)) (mul _)) ) | |
133 | ((then _ #(c)) . #(c) ) | |
134 | ((then (#(op) #(a)) #(b)) . (#(op) (then #(a) #(b))) ) | |
135 | ((then (#(op) #(k) #(a)) #(b)) . (#(op) #(k) (then #(a) #(b))) ) | |
136 | ) | |
137 | )) | |
138 | '(push 9 (push 2 (push 3 (mul (add _))))) | |
139 | ) | |
140 | ||
141 | (test 'reduce-term-3 | |
142 | (lambda () | |
143 | (reduce-term | |
144 | '(+ (const 9) | |
145 | (if (> (const 3) (const 2)) | |
146 | (* (const 2) (const 3)) | |
147 | (const 1))) | |
148 | '( | |
149 | ((const #(a)) . (push #(a) _) ) | |
150 | ((+ #(l) #(r)) . (then (then #(l) #(r)) (add _)) ) | |
151 | ((* #(l) #(r)) . (then (then #(l) #(r)) (mul _)) ) | |
152 | ((> #(l) #(r)) . (then (then #(l) #(r)) (gt _)) ) | |
153 | ||
154 | ((if #(q) #(t) #(f)) . | |
155 | (then #(q) (jfalse label: | |
156 | (then #(t) (jmp end: | |
157 | (label label: | |
158 | (then #(f) (label end: _))))))) ) | |
159 | ||
160 | ((gt (jfalse #(l) #(rest))) . (jle #(l) #(rest)) ) | |
161 | ||
162 | ((then _ #(c)) . #(c) ) | |
163 | ((then (#(op) #(a)) #(b)) . (#(op) (then #(a) #(b))) ) | |
164 | ((then (#(op) #(k) #(a)) #(b)) . (#(op) #(k) (then #(a) #(b))) ) | |
165 | ) | |
166 | )) | |
167 | '(push 9 (push 3 (push 2 (jle label: (push 2 (push 3 (mul (jmp end: | |
168 | (label label: (push 1 (label end: (add _)))))))))))) | |
169 | ) | |
170 | ||
171 | (load "preprocess.scm");--------------------------------------------------- | |
172 | ||
173 | (test 'preprocess-1 | |
174 | (lambda () | |
175 | (preprocess | |
176 | '( | |
177 | ( ; list of named terms | |
178 | (ast: (const a 4 (+ 3 (* a 3)))) ; a named term | |
179 | (stab: eot) | |
180 | (out: halt) | |
181 | ) | |
182 | ( ; list of compound-rules | |
183 | ((ast: foo => bar) (stab: bee => hive)) ; a compound-rule | |
184 | ) | |
185 | ) | |
186 | )) | |
187 | '#( | |
188 | #((const a 4 (+ 3 (* a 3))) eot halt) | |
189 | ((#(0 foo bar) #(1 bee hive))) | |
190 | ) | |
191 | ) | |
192 | ||
193 | (load "forest-rewrite.scm");-------------------------------------------------- | |
194 | ||
195 | (test 'rewrite-tree-1 | |
196 | (lambda () | |
197 | (rewrite-forest (preprocess | |
198 | '( | |
199 | ( | |
200 | (ast: (+ (const 9) (* (const 2) (const 3)))) | |
201 | ) | |
202 | ( | |
203 | ((ast: (const #(a)) => (push #(a) _) )) | |
204 | ((ast: (+ #(l) #(r)) => (then (then #(l) #(r)) (add _)) )) | |
205 | ((ast: (* #(l) #(r)) => (then (then #(l) #(r)) (mul _)) )) | |
206 | ((ast: (then _ #(c)) => #(c) )) | |
207 | ((ast: (then (#(op) #(a)) #(b)) => (#(op) (then #(a) #(b))) )) | |
208 | ((ast: (then (#(op) #(k) #(a)) #(b)) => (#(op) #(k) (then #(a) #(b))) )) | |
209 | ) | |
210 | ) | |
211 | ))) | |
212 | '#((push 9 (push 2 (push 3 (mul (add _)))))) | |
213 | ) | |
214 | ||
215 | (test 'rewrite-tree-2 | |
216 | (lambda () | |
217 | (rewrite-forest (preprocess | |
218 | '( | |
219 | ( | |
220 | (ast: (+ (const 9) | |
221 | (if (> (const 3) (const 2)) | |
222 | (* (const 2) (const 3)) | |
223 | (const 1))) | |
224 | ) | |
225 | ) | |
226 | ( | |
227 | ((ast: (const #(a)) => (push #(a) _) )) | |
228 | ((ast: (+ #(l) #(r)) => (then (then #(l) #(r)) (add _)) )) | |
229 | ((ast: (* #(l) #(r)) => (then (then #(l) #(r)) (mul _)) )) | |
230 | ((ast: (> #(l) #(r)) => (then (then #(l) #(r)) (gt _)) )) | |
231 | ||
232 | ((ast: (if #(q) #(t) #(f)) => | |
233 | (then #(q) (jfalse label: (then #(t) (jmp end: (label label: (then #(f) (label end: _))))))) )) | |
234 | ||
235 | ((ast: (gt (jfalse #(l) #(rest))) => (jle #(l) #(rest)) )) | |
236 | ||
237 | ((ast: (then _ #(c)) => #(c) )) | |
238 | ((ast: (then (#(op) #(a)) #(b)) => (#(op) (then #(a) #(b))) )) | |
239 | ((ast: (then (#(op) #(k) #(a)) #(b)) => (#(op) #(k) (then #(a) #(b))) )) | |
240 | ) | |
241 | ) | |
242 | ))) | |
243 | '#((push 9 (push 3 (push 2 (jle label: (push 2 (push 3 (mul (jmp end: | |
244 | (label label: (push 1 (label end: (add _))))))))))))) | |
245 | ) | |
246 | ||
247 | ;------------------------------------------------------------------- | |
248 | ||
249 | (test 'rewrite-forest-1 | |
250 | (lambda () | |
251 | (rewrite-forest (preprocess | |
252 | '( | |
253 | ( | |
254 | (ast: (+ 3 (* 2 3))) | |
255 | (out: halt) | |
256 | ) | |
257 | ( | |
258 | ((ast: #(a num) => _) (out: halt => (push #(a) halt))) | |
259 | ((ast: (+ _ _) => _) (out: halt => (add halt))) | |
260 | ((ast: (* _ _) => _) (out: halt => (mul halt))) | |
261 | ) | |
262 | ) | |
263 | ))) | |
264 | '#(_ (push 3 (push 2 (push 3 (mul (add halt)))))) | |
265 | ) | |
266 | ||
267 | (test 'rewrite-forest-2 | |
268 | (lambda () | |
269 | (rewrite-forest (preprocess | |
270 | '( | |
271 | ( | |
272 | (stab: (a 4 eot)) | |
273 | (ast: (+ 1 2 3 a 5 6 a 7 8 9)) | |
274 | ) | |
275 | ( | |
276 | ( (stab: (#(n) #(v) #(tab)) => (#(n) #(v) #(tab)) ) | |
277 | (ast: #(n sym) => #(v) ) ) | |
278 | ) | |
279 | ) | |
280 | ))) | |
281 | '#((a 4 eot) (+ 1 2 3 4 5 6 4 7 8 9)) | |
282 | ) | |
283 | ||
284 | (test 'rewrite-forest-3 | |
285 | (lambda () | |
286 | (rewrite-forest (preprocess | |
287 | '( | |
288 | ( | |
289 | (ast: (let a 4 (+ 3 (* a 3))) ) | |
290 | (stab: eot) | |
291 | (out: halt) | |
292 | ) | |
293 | ( | |
294 | ((ast: (let #(n sym) #(v) #(expr)) => #(expr) ) | |
295 | (stab: eot => (#(n) #(v) EOT) )) | |
296 | ((ast: #(n sym) => #(v) ) | |
297 | (stab: (#(n) #(v) #(tab)) => (#(n) #(v) #(tab)) )) | |
298 | ((ast: #(a num) => _ ) | |
299 | (out: halt => (push #(a) halt) )) | |
300 | ((ast: (+ _ _) => _ ) | |
301 | (out: halt => (add halt) )) | |
302 | ((ast: (* _ _) => _ ) | |
303 | (out: halt => (mul halt) )) | |
304 | ) | |
305 | ) | |
306 | ))) | |
307 | '#(_ (a 4 eot) (push 3 (push 4 (push 3 (mul (add halt)))))) | |
308 | ) | |
309 | ||
310 | ;(test 'rewrite-forest-4 | |
311 | ; (lambda () | |
312 | ; (rewrite-forest (preprocess | |
313 | ; '( | |
314 | ; ( | |
315 | ; (ast: (if (> 6 4) (print 1) (print 2)) ) | |
316 | ; (bpt: eot) | |
317 | ; (out: halt) | |
318 | ; ) | |
319 | ; ( | |
320 | ; ((ast: (> _ _) => _ ) | |
321 | ; (out: halt => (gt halt) )) | |
322 | ; ((ast: (print _) => _ ) | |
323 | ; (out: halt => (print halt) )) | |
324 | ; ((ast: #(a num) => _ ) | |
325 | ; (out: halt => (push #(a) halt) )) | |
326 | ; ((ast: (if _ #(t) #(p)) => (hmm #(t) #(p)) ) | |
327 | ; (out: halt => (test halt) )) | |
328 | ; ) | |
329 | ; ) | |
330 | ; ))) | |
331 | ; '#(_ (a 4 eot) (push 3 (push 4 (push 3 (mul (add halt)))))) | |
332 | ;) | |
333 |
0 | ; | |
1 | ; Bottom-Up Tree-Rewriting (Term-Rewriting) | |
2 | ; Chris Pressey, sometime late January 2006 | |
3 | ; | |
4 | ||
5 | ; Copyright (c)2008 Cat's Eye Technologies. All rights reserved. | |
6 | ; | |
7 | ; Redistribution and use in source and binary forms, with or without | |
8 | ; modification, are permitted provided that the following conditions | |
9 | ; are met: | |
10 | ; | |
11 | ; 1. Redistributions of source code must retain the above copyright | |
12 | ; notices, this list of conditions and the following disclaimer. | |
13 | ; 2. Redistributions in binary form must reproduce the above copyright | |
14 | ; notices, this list of conditions, and the following disclaimer in | |
15 | ; the documentation and/or other materials provided with the | |
16 | ; distribution. | |
17 | ; 3. Neither the names of the copyright holders nor the names of their | |
18 | ; contributors may be used to endorse or promote products derived | |
19 | ; from this software without specific prior written permission. | |
20 | ; | |
21 | ; THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
22 | ; ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES INCLUDING, BUT NOT | |
23 | ; LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS | |
24 | ; FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE | |
25 | ; COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, | |
26 | ; INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, | |
27 | ; BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | |
28 | ; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER | |
29 | ; CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
30 | ; LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN | |
31 | ; ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | |
32 | ; POSSIBILITY OF SUCH DAMAGE. | |
33 | ||
34 | ; | |
35 | ; Try unifying the pattern part of the given rule with the given term; | |
36 | ; if it matches, return a rewritten term based on the unifier and the | |
37 | ; replacement part of the rule; otherwise return #f. | |
38 | ; | |
39 | (define rewrite-single-term | |
40 | (lambda (term rules) | |
41 | (cond | |
42 | ((null? rules) | |
43 | #f) | |
44 | (else | |
45 | (let* ((rule (car rules)) | |
46 | (pattern (car rule)) | |
47 | (replacement (cdr rule)) | |
48 | (unifier (unify term pattern '()))) | |
49 | (cond | |
50 | (unifier | |
51 | (expand-vars replacement unifier)) | |
52 | (else | |
53 | (rewrite-single-term term (cdr rules))))))))) | |
54 | ||
55 | ; | |
56 | ; Rewrite the given term recursively, with the given set of rules, | |
57 | ; from the bottom up (preorder traversal.) Returns the rewritten | |
58 | ; term if successful, #f if not. rules is a list of pat-repl pairs. | |
59 | ; | |
60 | (define rewrite-bottom-up | |
61 | (lambda (term rules) | |
62 | (cond | |
63 | ((list? term) | |
64 | (let loop ((subterms term) ; first try to unify with each child | |
65 | (acc '())) ; keep track of subterms we've seen | |
66 | (cond | |
67 | ((null? subterms) ; no more children, try rewrite. | |
68 | (rewrite-single-term term rules)) | |
69 | (else | |
70 | (let* ((subterm (car subterms)) | |
71 | (rest (cdr subterms)) | |
72 | (new-subterm (rewrite-bottom-up subterm rules))) | |
73 | (cond | |
74 | (new-subterm ; this child succeeded. incorporate it | |
75 | (let* ((front (reverse acc)) | |
76 | (back (cons new-subterm rest)) | |
77 | (spliced-term (append front back))) | |
78 | spliced-term)) | |
79 | (else ; this child failed, try next one | |
80 | (loop (cdr subterms) (cons subterm acc))))))))) | |
81 | (else | |
82 | (rewrite-single-term term rules))))) | |
83 | ||
84 | ; | |
85 | ; Repeatedly rewrite the given term with the given rules until it | |
86 | ; is reduced into a normal form (if one exists for these rules.) | |
87 | ; Return the reduced term. | |
88 | ; | |
89 | (define reduce-term | |
90 | (lambda (term rules) | |
91 | (let* ((new-term (rewrite-bottom-up term rules))) | |
92 | (cond | |
93 | (new-term | |
94 | (reduce-term new-term rules)) | |
95 | (else | |
96 | term))))) |
0 | ; | |
1 | ; Simple support for unification & pattern matching | |
2 | ; Chris Pressey, late January 2006 | |
3 | ; | |
4 | ||
5 | ; Copyright (c)2008 Cat's Eye Technologies. All rights reserved. | |
6 | ; | |
7 | ; Redistribution and use in source and binary forms, with or without | |
8 | ; modification, are permitted provided that the following conditions | |
9 | ; are met: | |
10 | ; | |
11 | ; 1. Redistributions of source code must retain the above copyright | |
12 | ; notices, this list of conditions and the following disclaimer. | |
13 | ; 2. Redistributions in binary form must reproduce the above copyright | |
14 | ; notices, this list of conditions, and the following disclaimer in | |
15 | ; the documentation and/or other materials provided with the | |
16 | ; distribution. | |
17 | ; 3. Neither the names of the copyright holders nor the names of their | |
18 | ; contributors may be used to endorse or promote products derived | |
19 | ; from this software without specific prior written permission. | |
20 | ; | |
21 | ; THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
22 | ; ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES INCLUDING, BUT NOT | |
23 | ; LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS | |
24 | ; FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE | |
25 | ; COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, | |
26 | ; INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, | |
27 | ; BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | |
28 | ; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER | |
29 | ; CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
30 | ; LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN | |
31 | ; ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | |
32 | ; POSSIBILITY OF SUCH DAMAGE. | |
33 | ||
34 | ; | |
35 | ; Return #t if the given pattern is a variable, #f otherwise. | |
36 | ; | |
37 | (define pattern-var? | |
38 | (lambda (pattern) | |
39 | (vector? pattern))) ; just check that it is a vector | |
40 | ||
41 | ; | |
42 | ; Return the name of the given pattern variable. | |
43 | ; | |
44 | (define get-pattern-var-name | |
45 | (lambda (pattern-var) | |
46 | (vector-ref pattern-var 0))) ; just return the 1st element of the vector | |
47 | ||
48 | ; | |
49 | ; Return the optional predicate associated with the given pattern | |
50 | ; variable, which determines what kind of (Scheme) terms it can | |
51 | ; unify with. If no predicate is associated with the variable, | |
52 | ; a dummy always-true predicate is returned. | |
53 | ; | |
54 | (define get-pattern-var-pred | |
55 | (lambda (pattern-var) | |
56 | (cond ((< (vector-length pattern-var) 2) | |
57 | (lambda (x) #t)) | |
58 | (else | |
59 | (let ((term-type (vector-ref pattern-var 1))) | |
60 | (cond ((eqv? term-type 'num) | |
61 | (lambda (x) (number? x))) | |
62 | ((eqv? term-type 'sym) | |
63 | (lambda (x) (symbol? x))) | |
64 | (else | |
65 | (lambda (x) #f)))))))) | |
66 | ||
67 | ; | |
68 | ; Register that the named pattern variable should be associated with the given | |
69 | ; term in the given unifier. A new unifier containing the new variable-term | |
70 | ; association will be returned if possible; if it is not possible (i.e. the | |
71 | ; variable is already bound to a different term,) #f is returned. | |
72 | ; | |
73 | (define bind-pattern-var | |
74 | (lambda (term pattern unifier) | |
75 | (let* ((var-name (get-pattern-var-name pattern)) | |
76 | (var-pred? (get-pattern-var-pred pattern)) | |
77 | (pair (assq var-name unifier))) | |
78 | (cond | |
79 | ((not (var-pred? term)) | |
80 | #f) | |
81 | ((not (pair? pair)) ; if it's not in unifier, | |
82 | (cons (cons var-name term) unifier)) ; add it up front | |
83 | ((eqv? (cdr pair) term) ; already bound to the given term: alright | |
84 | unifier) | |
85 | (else ; already bound to something else: not good | |
86 | #f))))) | |
87 | ||
88 | ; | |
89 | ; Helper function. | |
90 | ; Given a term and a pattern, where we know both are lists, | |
91 | ; fold over both of them, unifying all the corresponding elements. | |
92 | ; | |
93 | (define unify-lists | |
94 | (lambda (term pattern unifier) | |
95 | (cond ((and (null? term) (null? pattern)) ; end of both | |
96 | unifier) | |
97 | ((or (null? term) (null? pattern)) ; end of one but not the other | |
98 | #f) | |
99 | (else | |
100 | (let ((new-unifier (unify (car term) (car pattern) unifier))) | |
101 | (if new-unifier | |
102 | (unify-lists (cdr term) (cdr pattern) new-unifier) | |
103 | #f)))))) | |
104 | ||
105 | ; | |
106 | ; Return #f if the term does not unify with the pattern, | |
107 | ; or a list of substitutions if it does unify. | |
108 | ; | |
109 | (define unify | |
110 | (lambda (term pattern unifier) | |
111 | (cond ((pattern-var? pattern) | |
112 | (bind-pattern-var term pattern unifier)) | |
113 | ((and (list? term) (list? pattern)) | |
114 | (unify-lists term pattern unifier)) | |
115 | ((eqv? term pattern) | |
116 | unifier) | |
117 | (else | |
118 | #f)))) | |
119 | ||
120 | ; | |
121 | ; Given a pattern and a unifier (set of substitutions,) return a term | |
122 | ; where all the variables in the pattern have been replaced by their | |
123 | ; associated term in the unifier. | |
124 | ; | |
125 | (define expand-vars | |
126 | (lambda (pattern unifier) | |
127 | (cond ((pattern-var? pattern) ; variable - replace if in unifier | |
128 | (let* ((pair (assq (get-pattern-var-name pattern) unifier))) | |
129 | (cond ((pair? pair) | |
130 | (cdr pair)) | |
131 | (else | |
132 | pattern)))) | |
133 | ((list? pattern) ; list - recurse | |
134 | (map (lambda (subpattern) | |
135 | (expand-vars subpattern unifier)) | |
136 | pattern)) | |
137 | (else ; ground term - leave it alone. | |
138 | pattern)))) |
0 | ; | |
1 | ; Utility functions used by forest-rewriting project | |
2 | ; Chris Pressey, late January 2006 | |
3 | ; | |
4 | ||
5 | ; Copyright (c)2008 Cat's Eye Technologies. All rights reserved. | |
6 | ; | |
7 | ; Redistribution and use in source and binary forms, with or without | |
8 | ; modification, are permitted provided that the following conditions | |
9 | ; are met: | |
10 | ; | |
11 | ; 1. Redistributions of source code must retain the above copyright | |
12 | ; notices, this list of conditions and the following disclaimer. | |
13 | ; 2. Redistributions in binary form must reproduce the above copyright | |
14 | ; notices, this list of conditions, and the following disclaimer in | |
15 | ; the documentation and/or other materials provided with the | |
16 | ; distribution. | |
17 | ; 3. Neither the names of the copyright holders nor the names of their | |
18 | ; contributors may be used to endorse or promote products derived | |
19 | ; from this software without specific prior written permission. | |
20 | ; | |
21 | ; THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
22 | ; ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES INCLUDING, BUT NOT | |
23 | ; LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS | |
24 | ; FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE | |
25 | ; COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, | |
26 | ; INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, | |
27 | ; BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | |
28 | ; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER | |
29 | ; CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT | |
30 | ; LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN | |
31 | ; ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | |
32 | ; POSSIBILITY OF SUCH DAMAGE. | |
33 | ||
34 | ; | |
35 | ; Sort a list using mergesort. | |
36 | ; | |
37 | (define mergesort | |
38 | (lambda (lst gt-pred?) | |
39 | (cond ((null? lst) | |
40 | lst) | |
41 | ((null? (cdr lst)) | |
42 | lst) | |
43 | (else | |
44 | (let* ((pair (split lst '() '())) | |
45 | (left (mergesort (car pair) gt-pred?)) | |
46 | (right (mergesort (cdr pair) gt-pred?))) | |
47 | (merge left right gt-pred? '())))))) | |
48 | ||
49 | ; | |
50 | ; Yield a pair of lists, each containing roughly half the | |
51 | ; elements of the given list. | |
52 | ; | |
53 | (define split | |
54 | (lambda (lst acc1 acc2) | |
55 | (cond | |
56 | ((null? lst) | |
57 | (cons (reverse acc1) (reverse acc2))) | |
58 | ((null? (cdr lst)) | |
59 | (cons (reverse (append lst acc1)) (reverse acc2))) | |
60 | (else | |
61 | (let* ((left (car lst)) | |
62 | (right (cadr lst)) | |
63 | (rest (cddr lst))) | |
64 | (split rest (cons left acc1) (cons right acc2))))))) | |
65 | ||
66 | ; | |
67 | ; Given two sorted lists, return a sorted list that contains | |
68 | ; all of the elements from both lists. | |
69 | ; | |
70 | (define merge | |
71 | (lambda (list1 list2 gt-pred? acc) | |
72 | (cond | |
73 | ((and (null? list1) (null? list2)) | |
74 | (reverse acc)) | |
75 | ((null? list1) | |
76 | (merge list1 (cdr list2) gt-pred? (cons (car list2) acc))) | |
77 | ((null? list2) | |
78 | (merge (cdr list1) list2 gt-pred? (cons (car list1) acc))) | |
79 | ((gt-pred? (car list1) (car list2)) | |
80 | (merge list1 (cdr list2) gt-pred? (cons (car list2) acc))) | |
81 | (else | |
82 | (merge (cdr list1) list2 gt-pred? (cons (car list1) acc)))))) | |
83 | ||
84 | ; | |
85 | ; Side-effect-free alternative to vector-set! | |
86 | ; | |
87 | (define vector-store | |
88 | (lambda (vec index item) | |
89 | (let loop ((items (vector->list vec)) | |
90 | (index index) | |
91 | (item item) | |
92 | (acc '())) | |
93 | (cond ((null? items) | |
94 | (list->vector (reverse acc))) | |
95 | ((zero? index) | |
96 | (loop (cdr items) (- index 1) item (cons item acc))) | |
97 | (else | |
98 | (loop (cdr items) (- index 1) item (cons (car items) acc))))))) | |
99 | ||
100 | ; | |
101 | ; Debugging output. | |
102 | ; | |
103 | (define print | |
104 | (lambda list | |
105 | (for-each display list))) | |
106 | ||
107 | (define println | |
108 | (lambda list | |
109 | (for-each display list) | |
110 | (newline))) | |
111 | ||
112 | ; | |
113 | ; Testing framework. | |
114 | ; | |
115 | (define test | |
116 | (lambda (test-name proc expected) | |
117 | (print "Running test: " test-name "... ") | |
118 | (let ((result (proc))) | |
119 | (cond | |
120 | ((equal? result expected) | |
121 | (println "passed.")) | |
122 | (else | |
123 | (println "FAILED!") | |
124 | (println "Expected: " expected) | |
125 | (println "Actual: " result)))))) |