--- /dev/null
+;; DERIVED FORMS
+
+;; define
+
+(define-macro (define args . body)
+ (if (pair? args)
+ (list 'define (car args) (join-lists (list 'lambda (cdr args)) body))
+ 'no-match))
+
+;; not
+
+(define-macro (not x)
+ (list 'if x #f #t))
+
+;; let
+
+(define-macro (let args . body)
+ (join-lists
+ (list (join-lists (list 'lambda (map (lambda (x) (car x)) args)) body))
+ (map (lambda (x) (car (cdr x))) args)))
+
+;; quasiquote/unquote (one nesting level only)
+
+((lambda ()
+ (define (qqhelper l)
+ (if (null? l)
+ l
+ (let ((head (car l))
+ (tail (cdr l)))
+
+ (if (pair? head)
+ (if (eq? (car head) 'unquote)
+ (list 'cons (car (cdr head)) (qqhelper tail))
+ (if (eq? (car head) 'unquote-splicing)
+ (list 'join-lists (car (cdr head)) (qqhelper tail))
+ (list 'cons (list 'quasiquote head) (qqhelper tail))))
+ (if (symbol? head)
+ (list 'cons (list 'quote head) (qqhelper tail))
+ (list 'cons head (qqhelper tail)))))))
+
+ (define-macro (quasiquote arg)
+ (if (not (pair? arg))
+ (list 'quote arg)
+ (qqhelper arg)))))
+
+;; begin
+
+(define-macro (begin . sequence)
+ `((lambda () ,@sequence)))
+
+;; caddr etc.
+
+(define-macro (caar l) `(car (car ,l)))
+(define-macro (cadr l) `(car (cdr ,l)))
+(define-macro (cdar l) `(cdr (car ,l)))
+(define-macro (cddr l) `(cdr (cdr ,l)))
+(define-macro (caaar l) `(car (car (car ,l))))
+(define-macro (caadr l) `(car (car (cdr ,l))))
+(define-macro (cadar l) `(car (cdr (car ,l))))
+(define-macro (caddr l) `(car (cdr (cdr ,l))))
+(define-macro (cdaar l) `(cdr (car (car ,l))))
+(define-macro (cdadr l) `(cdr (car (cdr ,l))))
+(define-macro (cddar l) `(cdr (cdr (car ,l))))
+(define-macro (cdddr l) `(cdr (cdr (cdr ,l))))
+(define-macro (cadddr l) `(car (cdr (cdr (cdr ,l)))))
+
+;; let*
+
+(define-macro (let* args . body)
+ (if (null? args)
+ `(let () ,@body)
+ `(let (,(car args))
+ (let* ,(cdr args) ,@body))))
+
+;; while
+
+(define-macro (while condition . body)
+ (let ((loop (gensym)))
+ `(begin
+ (define (,loop)
+ (if ,condition
+ (begin ,@body (,loop))))
+ (,loop))))
+
+;; cond
+
+((lambda ()
+ (define (cond-predicate clause) (car clause))
+ (define (cond-actions clause) (cdr clause))
+ (define (cond-else-clause? clause)
+ (eq? (cond-predicate clause) 'else))
+
+ (define (expand-clauses clauses)
+ (if (null? clauses)
+ (none)
+ (let ((first (car clauses))
+ (rest (cdr clauses)))
+ (if (cond-else-clause? first)
+ (if (null? rest)
+ `(begin ,@(cond-actions first))
+ (error "else clause isn't last in cond expression."))
+ `(if ,(cond-predicate first)
+ (begin ,@(cond-actions first))
+ ,(expand-clauses rest))))))
+
+ (define-macro (cond . clauses)
+ (if (null? clauses)
+ (error "cond requires at least one clause.")
+ (expand-clauses clauses)))))
+
+;; and
+
+((lambda ()
+ (define (expand-and-expressions expressions)
+ (let ((first (car expressions))
+ (rest (cdr expressions)))
+ (if (null? rest)
+ first
+ `(if ,first
+ ,(expand-and-expressions rest)
+ #f))))
+
+ (define-macro (and . expressions)
+ (if (null? expressions)
+ #t
+ (expand-and-expressions expressions)))))
+
+;; or
+
+((lambda ()
+ (define (expand-or-expressions expressions)
+ (let ((first (car expressions))
+ (rest (cdr expressions)))
+ (if (null? rest)
+ first
+ `(if ,first
+ #t
+ ,(expand-or-expressions rest)))))
+
+ (define-macro (or . expressions)
+ (if (null? expressions)
+ #f
+ (expand-or-expressions expressions)))))
+