2 ; Copyright © 2018 Keith Packard <keithp@keithp.com>
4 ; This program is free software; you can redistribute it and/or modify
5 ; it under the terms of the GNU General Public License as published by
6 ; the Free Software Foundation, either version 2 of the License, or
7 ; (at your option) any later version.
9 ; This program is distributed in the hope that it will be useful, but
10 ; WITHOUT ANY WARRANTY; without even the implied warranty of
11 ; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 ; General Public License for more details.
14 ; Advanced syntax, including vectors and floats
20 ((and (pair? a) (pair? b))
21 (and (equal? (car a) (car b))
22 (equal? (cdr a) (cdr b)))
24 ((and (vector? a) (vector? b) (= (vector-length a) (vector-length b)))
27 (equal? (vector-ref a i)
43 (_?_ (equal? '(a b c) '(a b c)) #t)
44 (_?_ (equal? '(a b c) '(a b b)) #f)
45 (_?_ (equal? #(1 2 3) #(1 2 3)) #t)
46 (_?_ (equal? #(1 2 3) #(4 5 6)) #f)
60 (define (constant? exp)
61 ; A constant value is either a pair starting with quote,
62 ; or anything which is neither a pair nor a symbol
65 (eq? (car exp) 'quote)
73 (define (combine-skeletons left right exp)
75 ((and (constant? left) (constant? right))
76 (cond ((and (eqv? (eval left) (car exp))
77 (eqv? (eval right) (cdr exp)))
81 (list 'quote (cons (eval left) (eval right)))
88 ((and (pair? right) (eq? (car right) 'list))
89 (cons 'list (cons left (cdr right)))
92 (list 'cons left right)
97 (define (expand-quasiquote exp nesting)
100 ; non cons -- constants
101 ; themselves, others are
105 (cond ((constant? exp)
114 ; check for an unquote exp and
115 ; add the param unquoted
117 ((and (eq? (car exp) 'unquote) (= (length exp) 2))
122 (combine-skeletons ''unquote
123 (expand-quasiquote (cdr exp) (- nesting 1))
128 ; nested quasi-quote --
129 ; construct the right
132 ((and (eq? (car exp) 'quasiquote) (= (length exp) 2))
133 (combine-skeletons ''quasiquote
134 (expand-quasiquote (cdr exp) (+ nesting 1))
138 ; unquote-splicing member,
139 ; compute the expansion of the
140 ; value and append the rest of
141 ; the quasiquote result to it
143 ((and (pair? (car exp))
144 (eq? (car (car exp)) 'unquote-splicing)
145 (= (length (car exp)) 2))
147 (list 'append (car (cdr (car exp)))
148 (expand-quasiquote (cdr exp) nesting))
151 (combine-skeletons (expand-quasiquote (car exp) (- nesting 1))
152 (expand-quasiquote (cdr exp) nesting)
157 ; for other lists, just glue
158 ; the expansion of the first
159 ; element to the expansion of
160 ; the rest of the list
162 (else (combine-skeletons (expand-quasiquote (car exp) nesting)
163 (expand-quasiquote (cdr exp) nesting)
168 (expand-quasiquote x 0)
173 ; `(q) -> (append (quote (q)))
174 ; `(a ,(+ 1 2)) -> (append (quote (a)) (list (+ 1 2)))
175 ; `(a ,@(list 1 2 3) -> (append (quote (a)) (list 1 2 3))
178 (_??_ `(hello ,(+ 1 2) ,@(list 1 2 3) `foo) '(hello 3 1 2 3 (quasiquote foo)))
180 ; define a set of local
181 ; variables all at once and
182 ; then evaluate a list of
185 ; (let (var-defines) sexprs)
187 ; where var-defines are either
197 ; (let ((x 1) (y)) (set! y (+ x 1)) y)
200 (macro (vars . exprs)
201 (define (make-names vars)
202 (cond ((not (null? vars))
203 (cons (car (car vars))
204 (make-names (cdr vars))))
209 ; the parameters to the lambda is a list
210 ; of nils of the right length
212 (define (make-vals vars)
213 (cond ((not (null? vars))
214 (cons (cond ((null? (cdr (car vars))) ())
216 (car (cdr (car vars))))
218 (make-vals (cdr vars))))
222 ; prepend the set operations
227 `((lambda ,(make-names vars) ,@exprs) ,@(make-vals vars))
232 (_??_ (let ((x 1) (y)) (set! y 2) (+ x y)) 3)
234 (define when (macro (test . l) `(cond (,test ,@l))))
236 (_??_ (when #t (+ 1 2)) 3)
237 (_??_ (when #f (+ 1 2)) #f)
239 (define unless (macro (test . l) `(cond ((not ,test) ,@l))))
241 (_??_ (unless #f (+ 2 3)) 5)
242 (_??_ (unless #t (+ 2 3)) #f)
244 (define (cdar l) (cdr (car l)))
246 (_??_ (cdar '((1 2) (3 4))) '(2))
248 (define (cddr l) (cdr (cdr l)))
250 (_??_ (cddr '(1 2 3)) '(3))
252 (define (caddr l) (car (cdr (cdr l))))
254 (_??_ (caddr '(1 2 3 4)) 3)
256 (define (reverse list)
260 (_r (cdr old) (cons (car old) new))
266 (_??_ (reverse '(1 2 3)) '(3 2 1))
273 (_m (- a 1) (cons b x))
284 (_??_ (make-list 10 'a) '(a a a a a a a a a a))
286 (_??_ (make-list 10) '(#f #f #f #f #f #f #f #f #f #f))
289 (lambda (proc . lists)
291 (cond ((null? (car lists)) #t)
293 (apply proc (map car lists))
303 (for-each (lambda (b) (set! a (+ a b))) '(1 2 3))
308 (_??_ (call-with-current-continuation
310 (for-each (lambda (x)
313 '(54 0 37 -3 245 19))
319 ; construct the body of the
320 ; case, dealing with the
321 ; lambda version ( => lambda)
325 ((eq? (car l) '=>) `(( ,(cadr l) __key__)))
329 ; Build the case elements, which is
330 ; simply a list of cond clauses
338 ((eq? (caar l) 'else)
339 `((else ,@(_unarrow (cdr (car l))))))
345 `((eqv? ,(caar l) __key__)
346 ,@(_unarrow (cdr (car l))))
352 ; now construct the overall
353 ; expression, using a lambda
354 ; to hold the computed value
355 ; of the test expression
358 (cond ,@(_case l))) ,test)
362 (_??_ (case 1 (1 "one") (2 "two") (3 => (lambda (x) (write (list "the value is" x)))) (12 "twelve") (else "else")) "one")
363 (_??_ (case 2 (1 "one") (2 "two") (3 => (lambda (x) (write (list "the value is" x)))) (12 "twelve") (else "else")) "two")
364 (_??_ (case 3 (1 "one") (2 "two") (3 => (lambda (x) (write (list "the value is" x)) "three")) (12 "twelve") (else "else")) "three")
365 (_??_ (case 4 (1 "one") (2 "two") (3 => (lambda (x) (write (list "the value is" x)))) (12 "twelve") (else "else")) "else")
366 (_??_ (case 12 (1 "one") (2 "two") (3 => (lambda (x) (write (list "the value is" x)))) (12 "twelve") (else "else")) "twelve")
369 (macro (vars test . cmds)
373 (if (null? (cddr (car v)))
375 (cons `(set! ,(caar v) ,(caddr (car v)))
381 `(let ,(map (lambda (v) (list (car v) (cadr v))) vars)
382 (while (not ,(car test))
391 (_??_ (do ((x 1 (+ x 1))
399 (_??_ (do ((vec (make-vector 5))
402 (vector-set! vec i i)) #(0 1 2 3 4))