altos/lisp: Make let distinct from let*
[fw/altos] / src / lisp / ao_lisp_const.lisp
1 ;
2 ; Copyright © 2016 Keith Packard <keithp@keithp.com>
3 ;
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.
8 ;
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.
13 ;
14 ; Lisp code placed in ROM
15
16                                         ; return a list containing all of the arguments
17 (set (quote list) (lexpr (l) l))
18
19 (set (quote set!)
20      (macro (name value rest)
21             (list
22              set
23              (list
24               quote
25               name)
26              value)
27             )
28      )
29
30 (set! append
31      (lexpr (args)
32             ((lambda (append-list append-lists)
33                (set! append-list
34                     (lambda (a b)
35                       (cond ((null? a) b)
36                             (else (cons (car a) (append-list (cdr a) b)))
37                             )
38                       )
39                     )
40                (set! append-lists
41                     (lambda (lists)
42                       (cond ((null? lists) lists)
43                             ((null? (cdr lists)) (car lists))
44                             (else (append-list (car lists) (append-lists (cdr lists))))
45                             )
46                       )
47                     )
48                (append-lists args)
49                ) () ())
50             )
51      )
52
53 (append '(a b c) '(d e f) '(g h i))
54
55                                         ; boolean operators
56
57 (set! or
58      (macro (l)
59             ((lambda (_or)
60                (set! _or
61                     (lambda (l)
62                       (cond ((null? l) #f)
63                             ((null? (cdr l))
64                              (car l))
65                             (else
66                              (list
67                               cond
68                               (list
69                                (car l))
70                               (list
71                                'else
72                                (_or (cdr l))
73                                )
74                               )
75                              )
76                             )
77                       )
78                     )
79                (_or l)) ())))
80
81                                         ; execute to resolve macros
82
83 (or #f #t)
84
85
86 (set! and
87      (macro (l)
88             ((lambda (_and)
89                (set! _and
90                     (lambda (l)
91                       (cond ((null? l) #t)
92                             ((null? (cdr l))
93                              (car l))
94                             (else
95                              (list
96                               cond
97                               (list
98                                (car l)
99                                (_and (cdr l))
100                                )
101                               )
102                              )
103                             )
104                       )
105                     )
106                (_and l)) ())
107             )
108      )
109
110
111                                         ; execute to resolve macros
112
113 (and #t #f)
114
115 (set! quasiquote
116   (macro (x rest)
117          ((lambda (constant? combine-skeletons expand-quasiquote)
118             (set! constant?
119                                         ; A constant value is either a pair starting with quote,
120                                         ; or anything which is neither a pair nor a symbol
121
122                  (lambda (exp)
123                    (cond ((pair? exp)
124                           (eq? (car exp) 'quote)
125                           )
126                          (else
127                           (not (symbol? exp))
128                           )
129                          )
130                    )
131                  )
132             (set! combine-skeletons
133                  (lambda (left right exp)
134                    (cond
135                     ((and (constant? left) (constant? right)) 
136                      (cond ((and (eqv? (eval left) (car exp))
137                                  (eqv? (eval right) (cdr exp)))
138                             (list 'quote exp)
139                             )
140                            (else
141                             (list 'quote (cons (eval left) (eval right)))
142                             )
143                            )
144                      )
145                     ((null? right)
146                      (list 'list left)
147                      )
148                     ((and (pair? right) (eq? (car right) 'list))
149                      (cons 'list (cons left (cdr right)))
150                      )
151                     (else
152                      (list 'cons left right)
153                      )
154                     )
155                    )
156                  )
157
158             (set! expand-quasiquote
159                  (lambda (exp nesting)
160                    (cond
161
162                                         ; non cons -- constants
163                                         ; themselves, others are
164                                         ; quoted
165
166                     ((not (pair? exp)) 
167                      (cond ((constant? exp)
168                             exp
169                             )
170                            (else
171                             (list 'quote exp)
172                             )
173                            )
174                      )
175
176                                         ; check for an unquote exp and
177                                         ; add the param unquoted
178
179                     ((and (eq? (car exp) 'unquote) (= (length exp) 2))
180                      (cond ((= nesting 0)
181                             (car (cdr exp))
182                             )
183                            (else
184                             (combine-skeletons ''unquote 
185                                                (expand-quasiquote (cdr exp) (- nesting 1))
186                                                exp))
187                            )
188                      )
189
190                                         ; nested quasi-quote --
191                                         ; construct the right
192                                         ; expression
193
194                     ((and (eq? (car exp) 'quasiquote) (= (length exp) 2))
195                      (combine-skeletons ''quasiquote 
196                                         (expand-quasiquote (cdr exp) (+ nesting 1))
197                                         exp))
198
199                                         ; check for an
200                                         ; unquote-splicing member,
201                                         ; compute the expansion of the
202                                         ; value and append the rest of
203                                         ; the quasiquote result to it
204
205                     ((and (pair? (car exp))
206                           (eq? (car (car exp)) 'unquote-splicing)
207                           (= (length (car exp)) 2))
208                      (cond ((= nesting 0)
209                             (list 'append (car (cdr (car exp)))
210                                   (expand-quasiquote (cdr exp) nesting))
211                             )
212                            (else
213                             (combine-skeletons (expand-quasiquote (car exp) (- nesting 1))
214                                                (expand-quasiquote (cdr exp) nesting)
215                                                exp))
216                            )
217                      )
218
219                                         ; for other lists, just glue
220                                         ; the expansion of the first
221                                         ; element to the expansion of
222                                         ; the rest of the list
223
224                     (else (combine-skeletons (expand-quasiquote (car exp) nesting)
225                                              (expand-quasiquote (cdr exp) nesting)
226                                              exp)
227                           )
228                     )
229                    )
230                  )
231             (expand-quasiquote x 0)
232             ) () () ())
233          )
234   )
235                                         ;
236                                         ; Define a variable without returning the value
237                                         ; Useful when defining functions to avoid
238                                         ; having lots of output generated.
239                                         ;
240                                         ; Also accepts the alternate
241                                         ; form for defining lambdas of
242                                         ; (define (name x y z) sexprs ...) 
243                                         ;
244
245 (set! define
246       (macro (first rest)
247
248                                         ; check for alternate lambda definition form
249
250              (cond ((list? first)
251                     (set! rest
252                           (append
253                            (list
254                             'lambda
255                             (cdr first))
256                            rest))
257                     (set! first (car first))
258                     )
259                    (else
260                     (set! rest (car rest))
261                     )
262                    )
263              `(begin
264                (set! ,first ,rest)
265                (quote ,first))
266              )
267       )
268
269                                         ; basic list accessors
270
271
272 (define (caar l) (car (car l)))
273
274 (define (cadr l) (car (cdr l)))
275
276 (define (cdar l) (cdr (car l)))
277
278 (define (caddr l) (car (cdr (cdr l))))
279
280 (define (list-tail x k)
281   (if (zero? k)
282       x
283     (list-tail (cdr x (- k 1)))
284     )
285   )
286
287 (define (list-ref x k)
288   (car (list-tail x k))
289   )
290
291                                         ; (if <condition> <if-true>)
292                                         ; (if <condition> <if-true> <if-false)
293
294 (define if
295   (macro (test args)
296          (cond ((null? (cdr args))
297                 `(cond (,test ,(car args)))
298                 )
299                (else
300                 `(cond (,test ,(car args))
301                        (else ,(cadr args)))
302                 )
303                )
304          )
305   )
306
307 (if (> 3 2) 'yes)
308 (if (> 3 2) 'yes 'no)
309 (if (> 2 3) 'no 'yes)
310 (if (> 2 3) 'no)
311
312                                         ; simple math operators
313
314 (define zero? (macro (value rest) `(eq? ,value 0)))
315
316 (zero? 1)
317 (zero? 0)
318 (zero? "hello")
319
320 (define positive? (macro (value rest) `(> ,value 0)))
321
322 (positive? 12)
323 (positive? -12)
324
325 (define negative? (macro (value rest) `(< ,value 0)))
326
327 (negative? 12)
328 (negative? -12)
329
330 (define (abs x) (if (>= x 0) x (- x)))
331
332 (abs 12)
333 (abs -12)
334
335 (define max (lexpr (first rest)
336                    (while (not (null? rest))
337                      (cond ((< first (car rest))
338                             (set! first (car rest)))
339                            )
340                      (set! rest (cdr rest))
341                      )
342                    first)
343   )
344
345 (max 1 2 3)
346 (max 3 2 1)
347
348 (define min (lexpr (first rest)
349                    (while (not (null? rest))
350                      (cond ((> first (car rest))
351                             (set! first (car rest)))
352                            )
353                      (set! rest (cdr rest))
354                      )
355                    first)
356   )
357
358 (min 1 2 3)
359 (min 3 2 1)
360
361 (define (even? x) (zero? (% x 2)))
362
363 (even? 2)
364 (even? -2)
365 (even? 3)
366 (even? -1)
367
368 (define (odd? x) (not (even? x)))
369
370 (odd? 2)
371 (odd? -2)
372 (odd? 3)
373 (odd? -1)
374
375
376                                         ; define a set of local
377                                         ; variables all at once and
378                                         ; then evaluate a list of
379                                         ; sexprs
380                                         ;
381                                         ; (let (var-defines) sexprs)
382                                         ;
383                                         ; where var-defines are either
384                                         ;
385                                         ; (name value)
386                                         ;
387                                         ; or
388                                         ;
389                                         ; (name)
390                                         ;
391                                         ; e.g.
392                                         ;
393                                         ; (let ((x 1) (y)) (set! y (+ x 1)) y)
394
395 (define let (macro (vars exprs)
396                 ((lambda (make-names make-vals)
397
398                                         ;
399                                         ; make the list of names in the let
400                                         ;
401
402                    (set! make-names (lambda (vars)
403                                       (cond ((not (null? vars))
404                                              (cons (car (car vars))
405                                                    (make-names (cdr vars))))
406                                             (else ())
407                                             )
408                                       )
409                          )
410
411                                         ; the parameters to the lambda is a list
412                                         ; of nils of the right length
413
414                    (set! make-vals (lambda (vars)
415                                      (cond ((not (null? vars))
416                                             (cons (cond ((null? (cdr (car vars))) ())
417                                                         (else
418                                                          (car (cdr (car vars))))
419                                                         )
420                                                   (make-vals (cdr vars))))
421                                            (else ())
422                                            )
423                                      )
424                          )
425                                         ; prepend the set operations
426                                         ; to the expressions
427
428                                         ; build the lambda.
429
430                    `((lambda ,(make-names vars) ,@exprs) ,@(make-vals vars))
431                    )
432                  ()
433                  ()
434                  )
435                 )
436      )
437                    
438
439 (let ((x 1) (y)) (set! y 2) (+ x y))
440
441                                         ; define a set of local
442                                         ; variables one at a time and
443                                         ; then evaluate a list of
444                                         ; sexprs
445                                         ;
446                                         ; (let* (var-defines) sexprs)
447                                         ;
448                                         ; where var-defines are either
449                                         ;
450                                         ; (name value)
451                                         ;
452                                         ; or
453                                         ;
454                                         ; (name)
455                                         ;
456                                         ; e.g.
457                                         ;
458                                         ; (let* ((x 1) (y)) (set! y (+ x 1)) y)
459
460 (define let* (macro (vars exprs)
461                 ((lambda (make-names make-exprs make-nils)
462
463                                         ;
464                                         ; make the list of names in the let
465                                         ;
466
467                    (set! make-names (lambda (vars)
468                                       (cond ((not (null? vars))
469                                              (cons (car (car vars))
470                                                    (make-names (cdr vars))))
471                                             (else ())
472                                             )
473                                       )
474                          )
475
476                                         ; the set of expressions is
477                                         ; the list of set expressions
478                                         ; pre-pended to the
479                                         ; expressions to evaluate
480
481                    (set! make-exprs (lambda (vars exprs)
482                                       (cond ((not (null? vars))
483                                              (cons
484                                               (list set
485                                                     (list quote
486                                                           (car (car vars))
487                                                           )
488                                                     (cond ((null? (cdr (car vars))) ())
489                                                           (else (cadr (car vars))))
490                                                     )
491                                               (make-exprs (cdr vars) exprs)
492                                               )
493                                              )
494                                             (else exprs)
495                                             )
496                                       )
497                          )
498
499                                         ; the parameters to the lambda is a list
500                                         ; of nils of the right length
501
502                    (set! make-nils (lambda (vars)
503                                      (cond ((not (null? vars)) (cons () (make-nils (cdr vars))))
504                                            (else ())
505                                            )
506                                      )
507                          )
508                                         ; prepend the set operations
509                                         ; to the expressions
510
511                    (set! exprs (make-exprs vars exprs))
512
513                                         ; build the lambda.
514
515                    `((lambda ,(make-names vars) ,@exprs) ,@(make-nils vars))
516                    )
517                  ()
518                  ()
519                  ()
520                  )
521                 )
522      )
523
524 (let* ((x 1)) x)
525
526 (define when (macro (test l) `(cond (,test ,@l))))
527
528 (when #t (write 'when))
529
530 (define unless (macro (test l) `(cond ((not ,test) ,@l))))
531
532 (unless #f (write 'unless))
533
534 (define (reverse list)
535   (let ((result ()))
536     (while (not (null? list))
537       (set! result (cons (car list) result))
538       (set! list (cdr list))
539       )
540     result)
541   )
542
543 (reverse '(1 2 3))
544
545 (define (list-tail x k)
546   (if (zero? k)
547       x
548     (list-tail (cdr x) (- k 1)))))
549
550 (list-tail '(1 2 3) 2)
551
552 (define (list-ref x k) (car (list-tail x k)))
553
554 (list-ref '(1 2 3) 2)
555     
556                                         ; recursive equality
557
558 (define (equal? a b)
559   (cond ((eq? a b) #t)
560         ((and (pair? a) (pair? b))
561          (and (equal? (car a) (car b))
562               (equal? (cdr a) (cdr b)))
563          )
564         (else #f)
565         )
566   )
567
568 (equal? '(a b c) '(a b c))
569 (equal? '(a b c) '(a b b))
570
571 (define member (lexpr (obj list test?)
572                       (cond ((null? list)
573                              #f
574                              )
575                             (else
576                              (if (null? test?) (set! test? equal?) (set! test? (car test?)))
577                              (if (test? obj (car list))
578                                  list
579                                (member obj (cdr list) test?))
580                              )
581                             )
582                       )
583   )
584
585 (member '(2) '((1) (2) (3)))
586
587 (member '(4) '((1) (2) (3)))
588
589 (define (memq obj list) (member obj list eq?))
590
591 (memq 2 '(1 2 3))
592
593 (memq 4 '(1 2 3))
594
595 (memq '(2) '((1) (2) (3)))
596
597 (define (memv obj list) (member obj list eqv?))
598
599 (memv 2 '(1 2 3))
600
601 (memv 4 '(1 2 3))
602
603 (memv '(2) '((1) (2) (3)))
604
605 (define (_assoc obj list test?)
606   (if (null? list)
607       #f
608     (if (test? obj (caar list))
609         (car list)
610       (_assoc obj (cdr list) test?)
611       )
612     )
613   )
614
615 (define (assq obj list) (_assoc obj list eq?))
616 (define (assv obj list) (_assoc obj list eqv?))
617 (define (assoc obj list) (_assoc obj list equal?))
618
619 (assq 'a '((a 1) (b 2) (c 3)))
620 (assv 'b '((a 1) (b 2) (c 3)))
621 (assoc '(c) '((a 1) (b 2) ((c) 3)))
622
623 (define char? integer?)
624
625 (char? #\q)
626 (char? "h")
627
628 (define (char-upper-case? c) (<= #\A c #\Z))
629
630 (char-upper-case? #\a)
631 (char-upper-case? #\B)
632 (char-upper-case? #\0)
633 (char-upper-case? #\space)
634
635 (define (char-lower-case? c) (<= #\a c #\a))
636
637 (char-lower-case? #\a)
638 (char-lower-case? #\B)
639 (char-lower-case? #\0)
640 (char-lower-case? #\space)
641
642 (define (char-alphabetic? c) (or (char-upper-case? c) (char-lower-case? c)))
643
644 (char-alphabetic? #\a)
645 (char-alphabetic? #\B)
646 (char-alphabetic? #\0)
647 (char-alphabetic? #\space)
648
649 (define (char-numeric? c) (<= #\0 c #\9))
650
651 (char-numeric? #\a)
652 (char-numeric? #\B)
653 (char-numeric? #\0)
654 (char-numeric? #\space)
655
656 (define (char-whitespace? c) (or (<= #\tab c #\return) (= #\space c)))
657
658 (char-whitespace? #\a)
659 (char-whitespace? #\B)
660 (char-whitespace? #\0)
661 (char-whitespace? #\space)
662
663 (define (char->integer c) c)
664 (define (integer->char c) char-integer)
665
666 (define (char-upcase c) (if (char-lower-case? c) (+ c (- #\A #\a)) c))
667
668 (char-upcase #\a)
669 (char-upcase #\B)
670 (char-upcase #\0)
671 (char-upcase #\space)
672
673 (define (char-downcase c) (if (char-upper-case? c) (+ c (- #\a #\A)) c))
674
675 (char-downcase #\a)
676 (char-downcase #\B)
677 (char-downcase #\0)
678 (char-downcase #\space)
679
680 (define string (lexpr (chars) (list->string chars)))
681
682 (display "apply\n")
683 (apply cons '(a b))
684
685 (define map (lexpr (proc lists)
686                    (let* ((args (lambda (lists)
687                                   (if (null? lists) ()
688                                     (cons (caar lists) (args (cdr lists))))))
689                           (next (lambda (lists)
690                                   (if (null? lists) ()
691                                     (cons (cdr (car lists)) (next (cdr lists))))))
692                           (domap (lambda (lists)
693                                    (if (null? (car lists)) ()
694                                      (cons (apply proc (args lists)) (domap (next lists)))
695                                      )))
696                           )
697                      (domap lists))))
698
699 (map cadr '((a b) (d e) (g h)))
700
701 (define for-each (lexpr (proc lists)
702                         (apply map proc lists)
703                         #t))
704
705 (for-each display '("hello" " " "world" "\n"))
706
707 (define _string-ml (lambda (strings)
708                              (if (null? strings) ()
709                                (cons (string->list (car strings)) (_string-ml (cdr strings))))))
710
711 (define string-map (lexpr (proc strings)
712                           (list->string (apply map proc (_string-ml strings))))))
713
714 (string-map (lambda (x) (+ 1 x)) "HAL")
715
716 (define string-for-each (lexpr (proc strings)
717                                (apply for-each proc (_string-ml strings))))
718
719 (string-for-each write-char "IBM\n")
720
721 (define newline (lambda () (write-char #\newline)))
722
723 (newline)
724
725 (call-with-current-continuation
726  (lambda (exit)
727    (for-each (lambda (x)
728                (write "test" x)
729                (if (negative? x)
730                    (exit x)))
731              '(54 0 37 -3 245 19))
732    #t))
733
734
735                                         ; `q -> (quote q)
736                                         ; `(q) -> (append (quote (q)))
737                                         ; `(a ,(+ 1 2)) -> (append (quote (a)) (list (+ 1 2)))
738                                         ; `(a ,@(list 1 2 3) -> (append (quote (a)) (list 1 2 3))
739
740
741
742 `(hello ,(+ 1 2) ,@(list 1 2 3) `foo)
743
744 (define repeat (macro (count rest)
745                        `(let ((__count__ ,count))
746                           (while (<= 0 (set! __count__ (- __count__ 1))) ,@rest))))
747
748 (repeat 2 (write 'hello))
749 (repeat 3 (write 'goodbye))
750
751 (define case (macro (test l)
752                     (let* ((_unarrow
753                                         ; construct the body of the
754                                         ; case, dealing with the
755                                         ; lambda version ( => lambda)
756                             
757                             (lambda (l)
758                               (cond ((null? l) l)
759                                     ((eq? (car l) '=>) `(( ,(cadr l) __key__)))
760                                     (else l))))
761                            (_case (lambda (l)
762
763                                         ; Build the case elements, which is
764                                         ; simply a list of cond clauses
765
766                                     (cond ((null? l) ())
767
768                                         ; else case
769
770                                           ((eq? (caar l) 'else)
771                                            `((else ,@(_unarrow (cdr (car l))))))
772
773                                         ; regular case
774                                           
775                                           (else
776                                            (cons
777                                             `((eqv? ,(caar l) __key__)
778                                               ,@(_unarrow (cdr (car l))))
779                                             (_case (cdr l)))
780                                            )
781                                           ))))
782
783                                         ; now construct the overall
784                                         ; expression, using a lambda
785                                         ; to hold the computed value
786                                         ; of the test expression
787
788                       `((lambda (__key__)
789                           (cond ,@(_case l))) ,test))))
790
791 (case 12 (1 "one") (2 "two") (3 => (lambda (x) (write "the value is" x))) (12 "twelve") (else "else"))
792
793 ;(define number->string (lexpr (arg opt)
794 ;                             (let ((base (if (null? opt) 10 (car opt)))
795                                         ;
796 ;
797