git.fiddlerwoaroof.com
lisp/2.lisp
2554f0f2
 (defpackage :fwoar.lisp-sandbox.2
   (:use :cl )
   (:export ))
 (in-package :fwoar.lisp-sandbox.2)
 (defvar *trace-depth* 0)
 
 (defclass bool () ())
 (progn
   (defvar true (make-instance 'bool))
   (defmethod print-object ((o (eql true)) s)
     (format s "#.~s" 'true)))
 (progn
   (defvar false (make-instance 'bool))
   (defmethod print-object ((o (eql false)) s)
     (format s "#.~s" 'false)))
 
 (defmacro define ((name &rest args) &body body)
   `(progn (defun ,name (,@args)
             ,@body)
           (defparameter ,name (function ,name))))
 
 (declaim (inline atom? symbol? string? number? char? boolean? vector?))
 (define (atom? exp)
   (atom exp))
 (define (null? it)
   (null it))
 (define (symbol? exp)
   (symbolp exp))
 (define (number? exp)
   (numberp exp))
 (define (string? exp)
   (stringp exp))
 (define (char? exp)
   (characterp exp))
 (define (boolean? exp)
   (or (eq exp false)
       (eq exp true)))
 (define (vector? exp)
   (vectorp exp))
 (define (eq? a b)
   (eq a b))
 (define (pair? it)
   (consp it))
 (define (set-cdr! it value)
   (rplacd it value))
 
 (define (->cl bool)
   (if (eq bool true) t nil))
 
 (defvar empty-begin 813)
 
 (define (wrong &rest args)
   (error "~{~a~^ ~}" args))
 
 (defvar env.init ())
 (defvar env.global (cons nil env.init))
 (defvar fenv.global (cons nil env.init))
 
 (defun key-eql (key)
   (lambda (a b)
     (eql (funcall key a)
          (funcall key b))))
 
 (defun do-adjoin (list item &rest r)
   (cons item
         (apply #'remove item list r)))
 (define-modify-macro adjoinf (item &rest r) do-adjoin)
 
 (defmacro definitial (name &optional (value nil value-p))
   (if value-p
       `(progn (adjoinf (cdr env.global)
                        (cons ',name ,value)
                        :test (key-eql #'car))
               ',name)
       `(progn (adjoinf (cdr env.global)
                        (cons ',name '#:uninit)
                        :test (key-eql #'car))
               ',name)))
 
 (defmacro definitial-function (name &optional (value nil value-p))
   (if value-p
       `(progn (adjoinf (cdr fenv.global)
                        (cons ',name ,value)
                        :test (key-eql #'car))
               ',name)
       `(progn (adjoinf (cdr fenv.global)
                        (cons ',name '#:uninit)
                        :test (key-eql #'car))
               ',name)))
 
 (defmacro defprimitive (name value arity)
   `(definitial-function ,name
        (lambda (values &optional env)
          (declare (ignore env))
          (if (= ,arity (length values))
              (apply ',value values)
              (wrong "incorrect arity" ',name ,arity values)))))
 
 (defmacro defprimitive-bool (name value arity)
   `(definitial-function ,name
        (lambda (values &optional env)
          (declare (ignore env))
          (if (= ,arity (length values))
              (if (apply ',value values)
                  true
                  false)
              (wrong "incorrect arity" ',name ,arity values)))))
 
 (define (extend env variables values)
   (cond ((pair? variables)
          (if (pair? values)
              (cons (cons (car variables) (car values))
                    (extend env (cdr variables) (cdr values)))
              (wrong "Too less values")))
         ((null? variables)
          (if (null? values)
              env
              (wrong "Too much values")))
         ((symbol? variables) (cons (cons variables values) env))))
 
 (define (invoke fn args)
   (if (functionp fn)
       (funcall fn args)
       (wrong "Not a function" fn)))
 
 (define (lookup id env)
   (if (pair? env)
       (if (eq? (caar env) id)
           (cdar env)
           (lookup id (cdr env)))
       (wrong "No such binding" id)))
 
 (define (f.make-function variables body env fenv)
   (lambda (values)
     (f.eprogn body
               (extend env
                       variables
                       values)
               fenv)))
 
 (define (update! id env value)
   (if (pair? env)
       (if (eq? (caar env) id)
           (progn (set-cdr! (car env) value)
                  value)
           (update! id (cdr env) value))
       (wrong "No such binding" id)))
 
 (define (f.evaluate e env fenv)
   (if (atom? e)
       (cond ((eq? e 't) true)
             ((eq? e 'f) false)
             ((or (number? e)
                  (string? e)
                  (char? e)
                  (boolean? e)
                  (vector? e))
              e)
             ((symbol? e) (lookup e env))
             ((wrong "Cannot evaluate" e)))
       (case (car e)
         ((quote) (cadr e))
         ((if) (if (->cl (f.evaluate (cadr e)
                                     env fenv))
                   (f.evaluate (caddr e)
                               env fenv)
                   (f.evaluate (cadddr e)
                               env fenv)))
         ((begin) (f.eprogn (cdr e)
                            env
                            fenv))
         ((set!) (update! (cadr e)
                          env
                          (f.evaluate (caddr e)
                                      env
                                      fenv)))
         ((function) (cond ((symbol? (cadr e))
                            (f.lookup (cadr e)
                                      fenv))
                           ((and (pair? (cadr e))
                                 (eq? (cadr e)
                                      'lambda))
                            (f.make-function (cadr (cadr e))
                                             (cddr (cadr e))
                                             env fenv))
                           ((wrong "Incorrect function" (cadr e)))))
         ((lambda) (make-function (cadr e)
                                  (cddr e)
                                  env))
         ((flet)
          (f.eprogn (cddr e)
                    env
                    (extend fenv
                            (mapcar 'car (cadr e))
                            (mapcar (lambda (def)
                                      (f.make-function (cadr def)
                                                       (cddr def)
                                                       env fenv))
                                    (cadr e)))))
         ((labels)
          (let ((new-fenv (extend fenv
                                  (mapcar 'car
                                          (cadr e))
                                  (mapcar (lambda (def)
                                            'void)
                                          (cadr e)))))
            (mapc (lambda (def)
                    (update! (car def)
                             new-fenv
                             (f.make-function (cadr def)
                                              (cddr def)
                                              env new-fenv)))
                  (cadr e))
            (f.eprogn (cddr e)
                      env new-fenv)))
         (t (f.evaluate-application (car e)
                                    (f.evlis (cdr e)
                                             env fenv)
                                    env fenv)))))
 (define (f.eprogn exps env fenv)
   (if (pair? exps)
       (if (pair? (cdr exps))
           (progn (f.evaluate (car exps) env fenv)
                  (eprogn (cdr exps)
                          env))
           (f.evaluate (car exps)
                       env fenv))
       empty-begin))
 
 (define (f.evlis exps env fenv)
   (if (pair? exps)
       (cons (f.evaluate (car exps) env fenv)
             (f.evlis (cdr exps) env fenv))
       ()))
 
 (define (f.evaluate-application fn args env fenv)
   (cond ((symbol? fn)
          (funcall (f.lookup fn fenv) args))
         ((and (pair? fn)
               (eq? (car fn)
                    'ambda))
          (f.eprogn (cddr fn)
                    (extend env
                            (cadr fn)
                            args)
                    fenv))
         ((wrong "Incorrect functional term" fn))))
 
 (define (f.lookup id fenv)
   (if (pair? fenv)
       (if (eq? (caar fenv)
                id)
           (cdar fenv)
           (f.lookup id
                     (cdr fenv)))
       (lambda (values)
         (declare (ignore values))
         (wrong "No such functional binding" id))))
 
 (defparameter def.extend
   (f.make-function '(env variables values)
                    '((if (pair? variables)
                          (if (pair? values)
                              (cons (cons (car variables) (car values))
                                    (extend env (cdr variables) (cdr values)))
                              (wrong "Too less values"))
                          (if (null? variables)
                              (if (null? values)
                                  env
                                  (wrong "Too much values"))
                              (if (symbol? variables)
                                  (cons (cons variables values) env)
                                  nil))))
                    env.global
                    fenv.global))
 
 (defun scheme-atom? (it)
   (if (atom it)
       true
       false))
 (defun scheme-not (it)
   (if (eq it true) false true))
 (defun scheme-eq? (a b)
   (if (eq a b)
       true
       false))
 (defun display (it)
   (format *trace-output* "~&~v,2@t ===> ~s~%" (* 2 *trace-depth*) it)
   it)
 
 (define (chapter2-scheme)
   (definitial apply
       (lambda (values)
         (apply (car values) (cdr values))))
 
   (definitial t true)
   (definitial f false)
   (definitial nil '())
   (definitial foo)
   (definitial bar)
   (definitial-function fib)
   (definitial-function fact)
   (definitial-function evaluate)
   (definitial-function evlis)
   (definitial-function eprogn)
   (definitial-function lookup)
   (definitial-function wrong)
   (definitial-function update!)
   (definitial-function make-function)
   (definitial-function invoke)
   (definitial-function foldl
       (f.make-function '(fn init list)
                        '((if (null? list)
                              init
                              (fn (foldl fn init (cdr list))
                                  (car list))))
                        env.global
                        fenv.global))
 
   (definitial-function extend def.extend)
   (definitial env.global env.global)
   (defprimitive atom? scheme-atom? 1)
   (defprimitive-bool number? number? 1)
   (defprimitive-bool vector? vector? 1)
   (defprimitive-bool char? char? 1)
   (defprimitive-bool boolean? boolean? 1)
   (defprimitive-bool string? string? 1)
   (defprimitive-bool symbol? symbol? 1)
   (defprimitive-bool pair? pair? 1)
   (defprimitive-bool function? functionp 1)
   (defprimitive-bool null? null? 1)
   (defprimitive not scheme-not 1)
   (defprimitive cons cons 2)
 
   (defprimitive car car 1)
   (defprimitive cdr cdr 1)
 
   (defprimitive caar caar 1)
   (defprimitive cadr cadr 1)
   (defprimitive cdar cdar 1)
   (defprimitive cddr cddr 1)
 
   (defprimitive #1=caaar #1# 1)
   (defprimitive #2=caadr #2# 1)
   (defprimitive #3=cadar #3# 1)
   (defprimitive #4=caddr #4# 1)
   (defprimitive #5=cdaar #5# 1)
   (defprimitive #6=cdadr #6# 1)
   (defprimitive #7=cddar #7# 1)
   (defprimitive #8=cdddr #8# 1)
 
   (defprimitive #9=caaaar #9# 1)
   (defprimitive #10=caaadr #10# 1)
   (defprimitive #11=caadar #11# 1)
   (defprimitive #12=caaddr #12# 1)
   (defprimitive #13=cadaar #13# 1)
   (defprimitive #14=cadadr #14# 1)
   (defprimitive #15=caddar #15# 1)
   (defprimitive #16=cadddr #16# 1)
   (defprimitive #17=cdaaar #17# 1)
   (defprimitive #18=cdaadr #18# 1)
   (defprimitive #19=cdadar #19# 1)
   (defprimitive #20=cdaddr #20# 1)
   (defprimitive #21=cddaar #21# 1)
   (defprimitive #22=cddadr #22# 1)
   (defprimitive #23=cdddar #23# 1)
   (defprimitive #24=cddddr #24# 1)
 
   (defprimitive set-cdr! rplacd 2)
   (defprimitive + + 2)
   (defprimitive * * 2)
   (defprimitive-bool = = 2)
   (defprimitive eq? scheme-eq? 2)
   (defprimitive < < 2)
   (defprimitive eql eql 2)
   (defprimitive display display 1)
   (definitial list
       (f.make-function 'v
                        '((if (null? v)
                              ()
                              (cons (car v)
                                    (list (cdr v)))))
                        env.global
                        fenv.global))
   (setf (cdr (assoc 'invoke fenv.global))
         (f.make-function '(fn args)
                          '((if (function? fn)
                                (apply fn args)
                                (wrong "Not a function" fn)))
                          env.global
                          fenv.global)
 
         (cdr (assoc 'make-function fenv.global))
         (f.make-function '(variables body env)
                          '((lambda (values)
                              (eprogn body
                                      (extend env variables values))))
                          env.global
                          fenv.global)
 
         (cdr (assoc 'update! fenv.global))
         (f.make-function '(id env value)
                          '((if (pair? env)
                                (if (eq? (caar env) id)
                                    (begin (set-cdr! (car env) value)
                                           value)
                                    (update! id (cdr env) value))
                                (wrong "No such binding" id)))
                          env.global
                          fenv.global)
 
         (cdr (assoc 'wrong fenv.global))
         (f.make-function '(a b)
                          '((display (cons a b)))
                          env.global
                          fenv.global)
 
         (cdr (assoc 'lookup fenv.global))
         (f.make-function '(id env)
                          '((if (pair? env)
                                (if (eq? (caar env) id)
                                    (cdar env)
                                    (lookup id (cdr env)))
                                (wrong "No such binding" id)))
                          env.global
                          fenv.global)
 
         (cdr (assoc 'evaluate fenv.global))
         (f.make-function '(e env)
                          '((if (atom? e)
                                (if (eq? e 't)
                                    t
                                    (if (eq? e 'f)
                                        f
                                        (if (if (number? e) t
                                                (if (string? e) t
                                                    (if (char? e) t
                                                        (if (boolean? e) t
                                                            (vector? e)))))
                                            e
                                            (if (symbol? e)
                                                (lookup e env)
                                                nil))))
                                ((lambda (case-var)
                                   (if (eq? case-var 'quote)
                                       (begin nil (cadr e))
                                       (if (eq? case-var 'if)
                                           (if (not (eq? (evaluate (cadr e) env) f))
                                               (evaluate (caddr e) env)
                                               (evaluate (cadddr e) env))
                                           (if (eq? case-var 'begin)
                                               (eprogn (cdr e) env)
                                               (if (eq? case-var 'set!)
                                                   (update! (cadr e) env (evaluate (caddr e) env))
                                                   (if (eq? case-var 'lambda)
                                                       (f.make-function (cadr e) (cddr e) env)
                                                       (invoke (evaluate (car e) env)
                                                               (evlis (cdr e) env))))))))
                                 (car e))))
                          env.global
                          fenv.global)
 
         (cdr (assoc 'evlis fenv.global))
         (f.make-function '(exps env)
                          '((if (pair? exps)
                                (cons (evaluate (car exps) env)
                                      (evlis (cdr exps) env))
                                ()))
                          env.global
                          fenv.global)
 
         (cdr (assoc 'eprogn fenv.global))
         (f.make-function '(exps env)
                          '((if (pair? exps)
                                (if (pair? (cdr exps))
                                    (begin (evaluate (car exps) env)
                                           (eprogn (cdr exps)
                                                   env))
                                    (evaluate (car exps)
                                              env))
                                ()))
                          env.global
                          fenv.global))
 
   (labels ((toplevel ()
              (fresh-line)
              (princ "> ")
              (with-simple-restart (continue "continue scheme repl")
                (princ (f.evaluate (let ((it (read)))
                                     (case it
                                       (:quit (return-from toplevel))
                                       (t it)))
                                   env.global
                                   fenv.global)))
              (terpri)
              (toplevel)))
     (toplevel)))