Last active
August 29, 2015 13:58
-
-
Save rgm/9967075 to your computer and use it in GitHub Desktop.
changes needed to turn the analyzing interpreter of SICP 4.1 to the nondeterministic interpreter of SICP 4.3
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
diff --git a/nondeterministic.scm b/nondeterministic.scm | |
index 1fab899..52e5b73 100644 | |
--- a/nondeterministic.scm | |
+++ b/nondeterministic.scm | |
@@ -1,5 +1,5 @@ | |
-(define (eval exp env) | |
- ((analyze exp) env)) | |
+(define (eval exp env succeed fail) | |
+ ((analyze exp) env succeed fail)) | |
(define (analyze exp) | |
(cond ((self-evaluating? exp) (analyze-self-evaluating exp)) | |
@@ -11,21 +11,25 @@ | |
((lambda? exp) (analyze-lambda exp)) | |
((begin? exp) (analyze-sequence exp)) | |
((cond? exp) (analyze (cond->if exp))) | |
+ ((amb? exp) (analyze-amb exp)) | |
((application? exp) (analyze-application exp)) | |
(else | |
(error "Unknown expression type -- ANALYZE" exp)))) | |
(define apply-in-underlying-scheme apply) ;; need it later for primitives | |
-(define (execute-application procedure arguments) | |
+(define (execute-application procedure arguments succeed fail) | |
(cond ((primitive-procedure? procedure) | |
- (apply-primitive-procedure procedure | |
- arguments)) | |
+ (succeed (apply-primitive-procedure procedure | |
+ arguments) | |
+ fail)) | |
((compound-procedure? procedure) | |
((procedure-body procedure) | |
(extend-environment (procedure-parameters procedure) | |
arguments | |
- (procedure-environment procedure)))) | |
+ (procedure-environment procedure)) | |
+ succeed | |
+ fail)) | |
(else | |
(error "Unknown procedure type -- EXECUTE-APPLICATION" procedure)))) | |
@@ -109,6 +113,9 @@ | |
(sequence->exp (cond-actions first)) | |
(expand-clauses rest)))))) | |
+(define (amb? exp) (tagged-list? exp 'amb)) | |
+(define (amb-choices exp) (cdr exp)) | |
+ | |
(define (application? exp) (pair? exp)) | |
(define (operator exp) (car exp)) | |
(define (operands exp) (cdr exp)) | |
@@ -131,53 +138,76 @@ | |
;; eval helpers | |
(define (analyze-self-evaluating exp) | |
- (lambda (env) exp)) | |
+ (lambda (env succeed fail) | |
+ (succeed exp fail))) | |
(define (analyze-quoted exp) | |
(let ((qval (text-of-quotation exp))) | |
- (lambda (env) qval))) | |
+ (lambda (env succeed fail) | |
+ (succeed qval fail)))) | |
(define (analyze-variable exp) | |
- (lambda (env) (lookup-variable-value exp env))) | |
+ (lambda (env succeed fail) (succeed (lookup-variable-value exp env) fail))) | |
(define (analyze-assignment exp) | |
(let ((var (assignment-variable exp)) | |
(vproc (analyze (assignment-value exp)))) | |
- (lambda (env) | |
- (set-variable-value! var | |
- (vproc env) | |
- env) | |
- 'ok))) | |
+ (lambda (env succeed fail) | |
+ (vproc env | |
+ (lambda (val fail2) | |
+ (let ((old-val (lookup-variable-value var env))) | |
+ (set-variable-value! var | |
+ val | |
+ env) | |
+ (succeed 'ok | |
+ (lambda () | |
+ (set-variable-value! var | |
+ old-val | |
+ env) | |
+ (fail2))))) | |
+ fail)))) | |
(define (analyze-definition exp) | |
(let ((var (definition-variable exp)) | |
(vproc (analyze (definition-value exp)))) | |
- (lambda (env) | |
- (define-variable! var | |
- (vproc env) | |
- env) | |
- 'ok))) | |
+ (lambda (env succeed fail) | |
+ (vproc env | |
+ (lambda (val fail2) | |
+ (define-variable! var | |
+ val | |
+ env) | |
+ (succeed 'ok fail2)) | |
+ fail)))) | |
(define (analyze-if exp) | |
(let ((pproc (analyze (if-predicate exp))) | |
(cproc (analyze (if-consequent exp))) | |
(aproc (analyze (if-alternative exp)))) | |
- (lambda (env) | |
- (if (pproc env) | |
- (cproc env) | |
- (aproc env))))) | |
+ (lambda (env succeed fail) | |
+ (pproc env | |
+ ;; success continuation for predicate eval | |
+ (lambda (pred-value fail2) | |
+ (if pred-value | |
+ (cproc env succeed fail2) | |
+ (aproc env succeed fail2))) | |
+ fail)))) | |
(define (analyze-lambda exp) | |
(let ((vars (lambda-parameters exp)) | |
(bproc (analyze-sequence (lambda-body exp)))) | |
- (lambda (env) | |
- (make-procedure vars | |
- bproc | |
- env)))) | |
+ (lambda (env succeed fail) | |
+ (succeed (make-procedure vars | |
+ bproc | |
+ env) | |
+ fail)))) | |
(define (analyze-sequence exps) | |
(define (sequentially proc1 proc2) | |
- (lambda (env) (proc1 env) (proc2 env))) | |
+ (lambda (env succeed fail) | |
+ (proc1 env | |
+ (lambda (proc1-value fail2) | |
+ (proc2 env succeed fail2)) | |
+ fail))) | |
(define (loop first-proc rest-procs) | |
(if (null? rest-procs) | |
first-proc | |
@@ -188,13 +218,47 @@ | |
(error "Empty sequence -- ANALYZE")) | |
(loop (car procs) (cdr procs)))) | |
+(define (analyze-amb exp) | |
+ (let ((cprocs (map analyze (amb-choices exp)))) | |
+ (lambda (env succeed fail) | |
+ (define (try-next choices) | |
+ (if (null? choices) | |
+ (fail) | |
+ ((car choices) env | |
+ succeed | |
+ (lambda () | |
+ (try-next (cdr choices)))))) | |
+ (try-next cprocs)))) | |
+ | |
(define (analyze-application exp) | |
(let ((fproc (analyze (operator exp))) | |
(aprocs (map analyze (operands exp)))) | |
- (lambda (env) | |
- (execute-application (fproc env) | |
- (map (lambda (aproc) (aproc env)) | |
- aprocs))))) | |
+ (lambda (env succeed fail) | |
+ (fproc env | |
+ (lambda (proc fail2) | |
+ (get-args aprocs | |
+ env | |
+ (lambda (args fail3) | |
+ (execute-application proc | |
+ args | |
+ succeed | |
+ fail3)) | |
+ fail2)) | |
+ fail)))) | |
+ | |
+(define (get-args aprocs env succeed fail) | |
+ (if (null? aprocs) | |
+ (succeed '() fail) | |
+ ((car aprocs) env | |
+ (lambda (arg fail2) | |
+ (get-args (cdr aprocs) | |
+ env | |
+ (lambda (args fail3) | |
+ (succeed (cons arg args) | |
+ fail3)) | |
+ fail2)) | |
+ fail))) | |
+ | |
;;; nested environments | |
@@ -279,6 +343,7 @@ | |
(list 'cdr cdr) | |
(list 'cons cons) | |
(list 'null? null?) | |
+ (list 'not not) | |
(list '+ +) | |
(list '- -) | |
(list '* *) | |
@@ -302,8 +367,8 @@ | |
;;; REPL | |
(define the-global-environment (setup-environment)) | |
-(define input-prompt ";;; A-Eval input") | |
-(define output-prompt ";;; A-Eval output") | |
+(define input-prompt ";;; Amb-Eval input") | |
+(define output-prompt ";;; Amb-Eval output") | |
(define (prompt-for-input string) | |
(newline) | |
@@ -325,11 +390,45 @@ | |
(display object))) | |
(define (driver-loop) | |
- (prompt-for-input input-prompt) | |
- (let ((input (read))) | |
- (let ((output (eval input the-global-environment))) | |
- (announce-output output-prompt) | |
- (user-print output))) | |
- (driver-loop)) | |
+ (define (internal-loop try-again) | |
+ (prompt-for-input input-prompt) | |
+ (let ((input (read))) | |
+ (if (eq? input 'try-again) | |
+ (try-again) | |
+ (begin | |
+ (newline) | |
+ (display ";;; starting a new problem ") | |
+ (eval input | |
+ the-global-environment | |
+ ;; success continuation | |
+ (lambda (output next-alternative) | |
+ (announce-output output-prompt) | |
+ (user-print output) | |
+ (internal-loop next-alternative)) | |
+ ;; failure continuation | |
+ (lambda () | |
+ (announce-output ";;; there are no more values of ") | |
+ (user-print input) | |
+ (driver-loop))))))) | |
+ (internal-loop | |
+ (lambda () | |
+ (newline) | |
+ (display ";;; no current problem") | |
+ (driver-loop)))) | |
+ | |
+(eval '(define require | |
+ (lambda (p) | |
+ (if (not p) (amb)))) | |
+ the-global-environment | |
+ (lambda (value fail) 'succeeded) | |
+ (lambda () 'failed)) | |
+ | |
+(eval '(define an-element-of | |
+ (lambda (items) | |
+ (require (not (null? items))) | |
+ (amb (car items) (an-element-of (cdr items))))) | |
+ the-global-environment | |
+ (lambda (value fail) 'succeeded) | |
+ (lambda () 'failed)) | |
(driver-loop) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment