Skip to content

Instantly share code, notes, and snippets.

@b0oh
Created October 22, 2012 13:12
Show Gist options
  • Select an option

  • Save b0oh/3931450 to your computer and use it in GitHub Desktop.

Select an option

Save b0oh/3931450 to your computer and use it in GitHub Desktop.
meta circular eval
(define (mceval exp env)
(cond ((self-evaluating? exp) exp)
((variable? exp) (lookup-variable-value exp env))
((quoted? exp) (text-of-quotation exp))
((assignment? exp) (eval-assignment exp env))
((definition? exp) (eval-definition exp env))
((if? exp) (eval-if exp env))
((lambda? exp)
(make-procedure (lambda-parameters exp)
(lambda-body exp)
env))
((begin? exp) (eval-sequnce (begin-actions exp) env))
((cond? exp) (mceval (cond->if exp) env))
((application? exp)
(mcapply (mceval (operator exp) env)
(list-of-values (operands exp) env)))
(else
(error "Unknown expression type -- EVAL" exp))))
(define (mcapply proc args)
(cond ((primitive-procedure? proc)
(apply-primitive-procedure proc args))
((compound-procedure? proc)
(eval-sequnce
(procedure-body proc)
(extend-environment
(procedure-parameters proc)
args
(procedure-environment proc))))
(else
(error "Unknown procedure type -- APPLY" proc))))
(define (tagged-list? exp tag)
(if (pair? exp)
(eq? (car exp) tag)
false))
(define (list-of-values exps env)
(if (no-operands? exps)
'()
(cons (mceval (first-operand exps) env)
(list-of-values (rest-operands exps) env))))
(define (eval-sequence exps env)
(cond ((last-exp? exps) (mceval (first-exp exps) env))
(else (mceval (first-exp exps) env)
(eval-sequence (rest-exps exps) env))))
(define (last-exp? seq) (null? (cdr seq)))
(define (first-exp seq) (car seq))
(define (rest-exps seq) (cdr seq))
;; numbers and strings
(define (self-evaluating? exp)
(cond ((number? exp) true)
((string? exp) true)
(else false)))
;; variable
(define (variable? exp) (symbol? exp))
;; quote
(define (quoted? exp) (tagged-list? exp 'quote))
(define (text-of-quotation exp) (cadr exp))
;; asignment
(define (assignment? exp)
(tagged-list? exp 'set!))
(define (eval-assignment exp env)
(set-variable-value! (assignment-variable exp)
(mceval (assignment-value exp) env)
env)
'ok)
(define (assignment-variable exp) (cadr exp))
(define (assignment-value exp) (caddr exp))
;; definition
(define (definition? exp) (tagged-list? exp 'define))
(define (eval-definition exp env)
(define-variable! (definition-variable exp)
(mceval (definition-value exp) env)
env)
'ok)
(define (definition-variable exp)
(if (symbol? (cadr exp))
(cadr exp)
(caadr exp)))
(define (definition-value exp)
(if (symbol? (cadr exp))
(caddr exp)
(make-lambda (cdadr exp)
(cddr exp))))
;; if
(define (if? exp) (tagged-list? exp 'if))
(define (if-predicate exp) (cadr exp))
(define (if-consequent exp) (caddr exp))
(define (if-alternative exp)
(if (not (null? (cdddr exp)))
(cadddr exp)
'false))
(define (make-if pred conseq alter)
(list 'if pred conseq alter))
(define (eval-if exp env)
(if (true? (mceval (if-predicate exp) env))
(mceval (if-consequent exp) env)
(mceval (if-alternative exp) env)))
(define (true? x) (not (eq? x false)))
(define (false? x) (eq? x false))
;; lambda
(define (lambda? exp) (tagged-list? exp 'lambda))
(define (lambda-parameters exp) (cadr exp))
(define (lambda-body exp) (cddr exp))
(define (make-lambda parameters body)
(cons 'lambda (cons parameters body)))
;; begin
(define (begin? exp) (tagged-list? exp 'begin))
(define (begin-actions exp) (cdr exp))
(define (sequence->exp seq)
(cond ((null? seq) seq)
((last-exp? seq) (first-exp seq))
(else (make-begin seq))))
(define (make-begin seq) (cons 'begin seq))
;;cond
(define (cond? exp) (tagged-list? exp 'cond))
(define (cond-clauses exp) (cdr exp))
(define (cond-else-clause? clause)
(eq? (cond-predicate clause) 'else))
(define (cond-extended-clause? clause)
(eq? '=> (car (cond-actions clause))))
(define (cond-predicate clause)
(car clause))
(define (cond-actions clause)
(cdr clause))
(define (cond-extended-action clause)
(cadr (cond-actions clause)))
(define (cond->if exp)
(expand-clauses (cond-clauses exp)))
(define (expand-clauses clauses)
(if (null? clauses)
'false
(let ((first (car clauses))
(rest (cdr clauses)))
(if (cond-else-clause? first)
(if (null? rest)
(sequence->exp (cond-actions first))
(error "ELSE clause not last -- COND->IF" clauses))
(if (cond-extended-clause? first)
(make-if (cond-predicate first)
(list (cond-extended-action first)
(cond-predicate first))
(expand-clauses rest))
(make-if (cond-predicate first)
(sequence->exp (cond-actions first))
(expand-clauses rest)))))))
;; application
(define (application? exp) (pair? exp))
(define (operator exp) (car exp))
(define (operands exp) (cdr exp))
(define (no-operands? ops) (null? ops))
(define (first-operand ops) (car ops))
(define (rest-operands ops) (cdr ops))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment