diff options
Diffstat (limited to 'src/scheme/ao_scheme_advanced_syntax.scheme')
| -rw-r--r-- | src/scheme/ao_scheme_advanced_syntax.scheme | 402 | 
1 files changed, 402 insertions, 0 deletions
| diff --git a/src/scheme/ao_scheme_advanced_syntax.scheme b/src/scheme/ao_scheme_advanced_syntax.scheme new file mode 100644 index 00000000..79d4ba65 --- /dev/null +++ b/src/scheme/ao_scheme_advanced_syntax.scheme @@ -0,0 +1,402 @@ +; +; Copyright © 2018 Keith Packard <keithp@keithp.com> +; +; This program is free software; you can redistribute it and/or modify +; it under the terms of the GNU General Public License as published by +; the Free Software Foundation, either version 2 of the License, or +; (at your option) any later version. +; +; This program is distributed in the hope that it will be useful, but +; WITHOUT ANY WARRANTY; without even the implied warranty of +; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU +; General Public License for more details. +; +; Advanced syntax, including vectors and floats + +(begin +  (def! equal? +    (lambda (a b) +      (cond ((eq? a b) #t) +	    ((and (pair? a) (pair? b)) +	     (and (equal? (car a) (car b)) +		  (equal? (cdr a) (cdr b))) +	     ) +	    ((and (vector? a) (vector? b) (= (vector-length a) (vector-length b))) +	     ((lambda (i l) +		(while (and (< i l) +			    (equal? (vector-ref a i) +				    (vector-ref b i))) +		       (set! i (+ i 1))) +		(eq? i l) +		) +	      0 +	      (vector-length a) +	      ) +	     ) +	    (else #f) +	    ) +      ) +    ) +  'equal? +  ) + +(_?_ (equal? '(a b c) '(a b c)) #t) +(_?_ (equal? '(a b c) '(a b b)) #f) +(_?_ (equal? #(1 2 3) #(1 2 3)) #t) +(_?_ (equal? #(1 2 3) #(4 5 6)) #f) + +(define (_??_ a b) +  (cond ((equal? a b) +	 a +	 ) +	(else +	 (exit 1) +	 ) +	) +  ) + +(define quasiquote +  (macro (x) +    (define (constant? exp) +					; A constant value is either a pair starting with quote, +					; or anything which is neither a pair nor a symbol + +      (cond ((pair? exp) +	     (eq? (car exp) 'quote) +	     ) +	    (else +	     (not (symbol? exp)) +	     ) +	    ) +      ) + +    (define (combine-skeletons left right exp) +      (cond +       ((and (constant? left) (constant? right))  +	(cond ((and (eqv? (eval left) (car exp)) +		    (eqv? (eval right) (cdr exp))) +	       (list 'quote exp) +	       ) +	      (else +	       (list 'quote (cons (eval left) (eval right))) +	       ) +	      ) +	) +       ((null? right) +	(list 'list left) +	) +       ((and (pair? right) (eq? (car right) 'list)) +	(cons 'list (cons left (cdr right))) +	) +       (else +	(list 'cons left right) +	) +       ) +      ) + +    (define (expand-quasiquote exp nesting) +      (cond + +					; non cons -- constants +					; themselves, others are +					; quoted + +       ((not (pair? exp))  +	(cond ((constant? exp) +	       exp +	       ) +	      (else +	       (list 'quote exp) +	       ) +	      ) +	) + +					; check for an unquote exp and +					; add the param unquoted + +       ((and (eq? (car exp) 'unquote) (= (length exp) 2)) +	(cond ((= nesting 0) +	       (car (cdr exp)) +	       ) +	      (else +	       (combine-skeletons ''unquote  +				  (expand-quasiquote (cdr exp) (- nesting 1)) +				  exp)) +	      ) +	) + +					; nested quasi-quote -- +					; construct the right +					; expression + +       ((and (eq? (car exp) 'quasiquote) (= (length exp) 2)) +	(combine-skeletons ''quasiquote  +			   (expand-quasiquote (cdr exp) (+ nesting 1)) +			   exp)) + +					; check for an +					; unquote-splicing member, +					; compute the expansion of the +					; value and append the rest of +					; the quasiquote result to it + +       ((and (pair? (car exp)) +	     (eq? (car (car exp)) 'unquote-splicing) +	     (= (length (car exp)) 2)) +	(cond ((= nesting 0) +	       (list 'append (car (cdr (car exp))) +		     (expand-quasiquote (cdr exp) nesting)) +	       ) +	      (else +	       (combine-skeletons (expand-quasiquote (car exp) (- nesting 1)) +				  (expand-quasiquote (cdr exp) nesting) +				  exp)) +	      ) +	) + +					; for other lists, just glue +					; the expansion of the first +					; element to the expansion of +					; the rest of the list + +       (else (combine-skeletons (expand-quasiquote (car exp) nesting) +				(expand-quasiquote (cdr exp) nesting) +				exp) +	     ) +       ) +      ) +    (expand-quasiquote x 0) +    ) +  ) + +					; `q -> (quote q) +					; `(q) -> (append (quote (q))) +					; `(a ,(+ 1 2)) -> (append (quote (a)) (list (+ 1 2))) +					; `(a ,@(list 1 2 3) -> (append (quote (a)) (list 1 2 3)) + + +(_??_ `(hello ,(+ 1 2) ,@(list 1 2 3) `foo) '(hello 3 1 2 3 (quasiquote foo))) + +					; define a set of local +					; variables all at once and +					; then evaluate a list of +					; sexprs +					; +					; (let (var-defines) sexprs) +					; +					; where var-defines are either +					; +					; (name value) +					; +					; or +					; +					; (name) +					; +					; e.g. +					; +					; (let ((x 1) (y)) (set! y (+ x 1)) y) + +(define let +  (macro (vars . exprs) +	 (define (make-names vars) +	   (cond ((not (null? vars)) +		  (cons (car (car vars)) +			(make-names (cdr vars)))) +		 (else ()) +		 ) +	   ) + +					; the parameters to the lambda is a list +					; of nils of the right length + +	 (define (make-vals vars) +	   (cond ((not (null? vars)) +		  (cons (cond ((null? (cdr (car vars))) ()) +			      (else +			       (car (cdr (car vars)))) +			      ) +			(make-vals (cdr vars)))) +		 (else ()) +		 ) +	   ) +					; prepend the set operations +					; to the expressions + +					; build the lambda. + +	 `((lambda ,(make-names vars) ,@exprs) ,@(make-vals vars)) +	 ) +     ) +		    + +(_??_ (let ((x 1) (y)) (set! y 2) (+ x y)) 3) + +(define when (macro (test . l) `(cond (,test ,@l)))) + +(_??_ (when #t (+ 1 2)) 3) +(_??_ (when #f (+ 1 2)) #f) + +(define unless (macro (test . l) `(cond ((not ,test) ,@l)))) + +(_??_ (unless #f (+ 2 3)) 5) +(_??_ (unless #t (+ 2 3)) #f) + +(define (cdar l) (cdr (car l))) + +(_??_ (cdar '((1 2) (3 4))) '(2)) + +(define (cddr l) (cdr (cdr l))) + +(_??_ (cddr '(1 2 3)) '(3)) + +(define (caddr l) (car (cdr (cdr l)))) + +(_??_ (caddr '(1 2 3 4)) 3) + +(define (reverse list) +  (define (_r old new) +    (if (null? old) +	new +	(_r (cdr old) (cons (car old) new)) +	) +    ) +  (_r list ()) +  ) + +(_??_ (reverse '(1 2 3)) '(3 2 1)) + +(define make-list +  (lambda (a . b) +    (define (_m a x) +      (if (zero? a) +	  x +	  (_m (- a 1) (cons b x)) +	  ) +      ) +    (if (null? b) +	(set! b #f) +	(set! b (car b)) +	) +    (_m a '()) +    ) +  ) +     +(_??_ (make-list 10 'a) '(a a a a a a a a a a)) + +(_??_ (make-list 10) '(#f #f #f #f #f #f #f #f #f #f)) + +(define for-each +  (lambda (proc . lists) +    (define (_f lists) +      (cond ((null? (car lists)) #t) +	    (else +	     (apply proc (map car lists)) +	     (_f (map cdr lists)) +	     ) +	    ) +      ) +    (_f lists) +    ) +  ) + +(_??_ (let ((a 0)) +	(for-each (lambda (b) (set! a (+ a b))) '(1 2 3)) +	a +	) +      6) +       +(_??_ (call-with-current-continuation +       (lambda (exit) +	 (for-each (lambda (x) +		     (if (negative? x) +			 (exit x))) +		   '(54 0 37 -3 245 19)) +	 #t)) +      -3) + +(define case +  (macro (test . l) +					; construct the body of the +					; case, dealing with the +					; lambda version ( => lambda) + +	 (define (_unarrow l) +	   (cond ((null? l) l) +		 ((eq? (car l) '=>) `(( ,(cadr l) __key__))) +		 (else l)) +	   ) + +					; Build the case elements, which is +					; simply a list of cond clauses + +	 (define (_case l) + +	   (cond ((null? l) ()) + +					; else case + +		 ((eq? (caar l) 'else) +		  `((else ,@(_unarrow (cdr (car l)))))) + +					; regular case +		  +		 (else +		  (cons +		   `((eqv? ,(caar l) __key__) +		     ,@(_unarrow (cdr (car l)))) +		   (_case (cdr l))) +		  ) +		 ) +	   ) + +					; now construct the overall +					; expression, using a lambda +					; to hold the computed value +					; of the test expression + +	 `((lambda (__key__) +	     (cond ,@(_case l))) ,test) +	 ) +  ) + +(_??_ (case 1 (1 "one") (2 "two") (3 => (lambda (x) (write (list "the value is" x)))) (12 "twelve") (else "else")) "one") +(_??_ (case 2 (1 "one") (2 "two") (3 => (lambda (x) (write (list "the value is" x)))) (12 "twelve") (else "else")) "two") +(_??_ (case 3 (1 "one") (2 "two") (3 => (lambda (x) (write (list "the value is" x)) "three")) (12 "twelve") (else "else")) "three") +(_??_ (case 4 (1 "one") (2 "two") (3 => (lambda (x) (write (list "the value is" x)))) (12 "twelve") (else "else")) "else") +(_??_ (case 12 (1 "one") (2 "two") (3 => (lambda (x) (write (list "the value is" x)))) (12 "twelve") (else "else")) "twelve") + +(define do +  (macro (vars test . cmds) +    (define (_step v) +      (if (null? v) +	  '() +	  (if (null? (cddr (car v))) +	      (_step (cdr v)) +	      (cons `(set! ,(caar v) ,(caddr (car v))) +		    (_step (cdr v)) +		    ) +	      ) +	  ) +      ) +    `(let ,(map (lambda (v) (list (car v) (cadr v))) vars) +       (while (not ,(car test)) +	      ,@cmds +	      ,@(_step vars) +	      ) +       ,@(cdr test) +       ) +    ) +  ) + +(_??_ (do ((x 1 (+ x 1)) +	   (y 0) +	   ) +	  ((= x 10) y) +	(set! y (+ y x)) +	) +      45) + +(_??_ (do ((vec (make-vector 5)) +	   (i 0 (+ i 1))) +	  ((= i 5) vec) +	(vector-set! vec i i)) #(0 1 2 3 4)) | 
