2023-10-19 22:01:00 +00:00
|
|
|
|
;; Code from the book adapted for racket and my existing support code
|
|
|
|
|
|
|
|
|
|
#lang sicp
|
|
|
|
|
|
2023-11-01 22:50:31 +00:00
|
|
|
|
(#%require "amb-utilities.rkt"
|
|
|
|
|
"syntax.rkt"
|
2023-10-19 22:01:00 +00:00
|
|
|
|
"environment.rkt"
|
|
|
|
|
"common.rkt"
|
2023-11-04 21:13:32 +00:00
|
|
|
|
"special-forms.rkt"
|
|
|
|
|
"timing.rkt")
|
2023-10-19 22:01:00 +00:00
|
|
|
|
|
2023-11-04 21:16:57 +00:00
|
|
|
|
(#%require (only racket current-process-milliseconds))
|
|
|
|
|
(#%require (only racket string-append))
|
|
|
|
|
|
2023-10-20 16:23:52 +00:00
|
|
|
|
(#%provide ambeval
|
2023-11-04 21:16:20 +00:00
|
|
|
|
amb-driver-loop
|
|
|
|
|
amb-eval-program)
|
2023-10-20 16:23:52 +00:00
|
|
|
|
|
2023-10-19 22:01:00 +00:00
|
|
|
|
(define (amb? exp) (tagged-list? exp 'amb))
|
|
|
|
|
(define (amb-choices exp) (cdr exp))
|
|
|
|
|
|
|
|
|
|
;; analyze from 4.1.6, with clause from 4.3.3 added
|
|
|
|
|
;; and also support for Let
|
|
|
|
|
(define (analyze exp)
|
|
|
|
|
(cond ((self-evaluating? exp)
|
|
|
|
|
(analyze-self-evaluating exp))
|
|
|
|
|
((quoted? exp) (analyze-quoted exp))
|
|
|
|
|
((variable? exp) (analyze-variable exp))
|
|
|
|
|
((assignment? exp) (analyze-assignment exp))
|
|
|
|
|
((definition? exp) (analyze-definition exp))
|
|
|
|
|
((if? exp) (analyze-if exp))
|
|
|
|
|
((lambda? exp) (analyze-lambda exp))
|
|
|
|
|
((begin? exp) (analyze-sequence (begin-actions exp)))
|
|
|
|
|
((cond? exp) (analyze (cond->if exp)))
|
|
|
|
|
((let? exp) (analyze (let->combination exp))) ;**
|
|
|
|
|
((amb? exp) (analyze-amb exp)) ;**
|
|
|
|
|
((application? exp) (analyze-application exp))
|
|
|
|
|
(else
|
|
|
|
|
(error "Unknown expression type -- ANALYZE" exp))))
|
|
|
|
|
|
|
|
|
|
(define (ambeval exp env succeed fail)
|
|
|
|
|
((analyze exp) env succeed fail))
|
|
|
|
|
|
|
|
|
|
;;;Simple expressions
|
|
|
|
|
|
|
|
|
|
(define (analyze-self-evaluating exp)
|
|
|
|
|
(lambda (env succeed fail)
|
|
|
|
|
(succeed exp fail)))
|
|
|
|
|
|
|
|
|
|
(define (analyze-quoted exp)
|
|
|
|
|
(let ((qval (text-of-quotation exp)))
|
|
|
|
|
(lambda (env succeed fail)
|
|
|
|
|
(succeed qval fail))))
|
|
|
|
|
|
|
|
|
|
(define (analyze-variable exp)
|
|
|
|
|
(lambda (env succeed fail)
|
|
|
|
|
(succeed (lookup-variable-value exp env)
|
|
|
|
|
fail)))
|
|
|
|
|
|
|
|
|
|
(define (analyze-lambda exp)
|
|
|
|
|
(let ((vars (lambda-parameters exp))
|
|
|
|
|
(bproc (analyze-sequence (lambda-body exp))))
|
|
|
|
|
(lambda (env succeed fail)
|
|
|
|
|
(succeed (make-procedure vars bproc env)
|
|
|
|
|
fail))))
|
|
|
|
|
|
|
|
|
|
;;;Conditionals and sequences
|
|
|
|
|
|
|
|
|
|
(define (analyze-if exp)
|
|
|
|
|
(let ((pproc (analyze (if-predicate exp)))
|
|
|
|
|
(cproc (analyze (if-consequent exp)))
|
|
|
|
|
(aproc (analyze (if-alternative exp))))
|
|
|
|
|
(lambda (env succeed fail)
|
|
|
|
|
(pproc env
|
|
|
|
|
;; success continuation for evaluating the predicate
|
|
|
|
|
;; to obtain pred-value
|
|
|
|
|
(lambda (pred-value fail2)
|
|
|
|
|
(if (true? pred-value)
|
|
|
|
|
(cproc env succeed fail2)
|
|
|
|
|
(aproc env succeed fail2)))
|
|
|
|
|
;; failure continuation for evaluating the predicate
|
|
|
|
|
fail))))
|
|
|
|
|
|
|
|
|
|
(define (analyze-sequence exps)
|
|
|
|
|
(define (sequentially a b)
|
|
|
|
|
(lambda (env succeed fail)
|
|
|
|
|
(a env
|
|
|
|
|
;; success continuation for calling a
|
|
|
|
|
(lambda (a-value fail2)
|
|
|
|
|
(b env succeed fail2))
|
|
|
|
|
;; failure continuation for calling a
|
|
|
|
|
fail)))
|
|
|
|
|
(define (loop first-proc rest-procs)
|
|
|
|
|
(if (null? rest-procs)
|
|
|
|
|
first-proc
|
|
|
|
|
(loop (sequentially first-proc (car rest-procs))
|
|
|
|
|
(cdr rest-procs))))
|
|
|
|
|
(let ((procs (map analyze exps)))
|
|
|
|
|
(if (null? procs)
|
|
|
|
|
(error "Empty sequence -- ANALYZE"))
|
|
|
|
|
(loop (car procs) (cdr procs))))
|
|
|
|
|
|
|
|
|
|
;;;Definitions and assignments
|
|
|
|
|
|
|
|
|
|
(define (analyze-definition exp)
|
|
|
|
|
(let ((var (definition-variable exp))
|
|
|
|
|
(vproc (analyze (definition-value exp))))
|
|
|
|
|
(lambda (env succeed fail)
|
|
|
|
|
(vproc env
|
|
|
|
|
(lambda (val fail2)
|
|
|
|
|
(define-variable! var val env)
|
|
|
|
|
(succeed 'ok fail2))
|
|
|
|
|
fail))))
|
|
|
|
|
|
|
|
|
|
(define (analyze-assignment exp)
|
|
|
|
|
(let ((var (assignment-variable exp))
|
|
|
|
|
(vproc (analyze (assignment-value exp))))
|
|
|
|
|
(lambda (env succeed fail)
|
|
|
|
|
(vproc env
|
|
|
|
|
(lambda (val fail2) ; *1*
|
|
|
|
|
(let ((old-value
|
|
|
|
|
(lookup-variable-value var env)))
|
|
|
|
|
(set-variable-value! var val env)
|
|
|
|
|
(succeed 'ok
|
|
|
|
|
(lambda () ; *2*
|
|
|
|
|
(set-variable-value! var
|
|
|
|
|
old-value
|
|
|
|
|
env)
|
|
|
|
|
(fail2)))))
|
|
|
|
|
fail))))
|
|
|
|
|
|
|
|
|
|
;;;Procedure applications
|
|
|
|
|
|
|
|
|
|
(define (analyze-application exp)
|
|
|
|
|
(let ((fproc (analyze (operator exp)))
|
|
|
|
|
(aprocs (map analyze (operands exp))))
|
|
|
|
|
(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
|
|
|
|
|
;; success continuation for this aproc
|
|
|
|
|
(lambda (arg fail2)
|
|
|
|
|
(get-args (cdr aprocs)
|
|
|
|
|
env
|
|
|
|
|
;; success continuation for recursive
|
|
|
|
|
;; call to get-args
|
|
|
|
|
(lambda (args fail3)
|
|
|
|
|
(succeed (cons arg args)
|
|
|
|
|
fail3))
|
|
|
|
|
fail2))
|
|
|
|
|
fail)))
|
|
|
|
|
|
|
|
|
|
(define (execute-application proc args succeed fail)
|
|
|
|
|
(cond ((primitive-procedure? proc)
|
|
|
|
|
(succeed (apply-primitive-procedure proc args)
|
|
|
|
|
fail))
|
|
|
|
|
((compound-procedure? proc)
|
|
|
|
|
((procedure-body proc)
|
|
|
|
|
(extend-environment (procedure-parameters proc)
|
|
|
|
|
args
|
|
|
|
|
(procedure-environment proc))
|
|
|
|
|
succeed
|
|
|
|
|
fail))
|
|
|
|
|
(else
|
|
|
|
|
(error
|
|
|
|
|
"Unknown procedure type -- EXECUTE-APPLICATION"
|
|
|
|
|
proc))))
|
|
|
|
|
|
|
|
|
|
;;;amb expressions
|
|
|
|
|
|
|
|
|
|
(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))))
|
|
|
|
|
|
|
|
|
|
;;;Driver loop
|
|
|
|
|
|
|
|
|
|
(define input-prompt ";;; Amb-Eval input:")
|
|
|
|
|
(define output-prompt ";;; Amb-Eval value:")
|
|
|
|
|
|
2023-11-04 21:16:20 +00:00
|
|
|
|
(define (amb-driver-loop)
|
2023-10-19 22:01:00 +00:00
|
|
|
|
(define env (setup-environment))
|
2023-11-04 21:16:20 +00:00
|
|
|
|
(amb-eval-program-in-env amb-utilities-program env)
|
2023-11-04 21:16:57 +00:00
|
|
|
|
(define start-time 0)
|
2023-11-09 21:55:49 +00:00
|
|
|
|
(define (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 ")
|
2023-11-30 23:24:17 +00:00
|
|
|
|
(newline)
|
2023-11-09 21:55:49 +00:00
|
|
|
|
(set! start-time (current-process-milliseconds))
|
|
|
|
|
(ambeval input
|
|
|
|
|
env
|
|
|
|
|
;; ambeval success
|
|
|
|
|
(lambda (val next-alternative)
|
|
|
|
|
(newline)
|
|
|
|
|
(announce-output output-prompt)
|
|
|
|
|
(display (- (current-process-milliseconds) start-time))
|
|
|
|
|
(newline)
|
|
|
|
|
(user-print val)
|
|
|
|
|
(internal-loop next-alternative))
|
|
|
|
|
;; ambeval failure
|
|
|
|
|
(lambda ()
|
|
|
|
|
(announce-output
|
|
|
|
|
";;; There are no more values of")
|
|
|
|
|
(display (- (current-process-milliseconds) start-time))
|
|
|
|
|
(newline)
|
|
|
|
|
(user-print input)
|
|
|
|
|
(driver-loop)))))))
|
|
|
|
|
(internal-loop
|
|
|
|
|
(lambda ()
|
|
|
|
|
(newline)
|
|
|
|
|
(display ";;; There is no current problem")
|
|
|
|
|
(driver-loop))))
|
|
|
|
|
(driver-loop))
|
2023-10-19 22:01:00 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
;;; Support for Let (as noted in footnote 56, p.428)
|
|
|
|
|
|
|
|
|
|
(define (let? exp) (tagged-list? exp 'let))
|
|
|
|
|
(define (let-bindings exp) (cadr exp))
|
|
|
|
|
(define (let-body exp) (cddr exp))
|
|
|
|
|
|
|
|
|
|
(define (let-var binding) (car binding))
|
|
|
|
|
(define (let-val binding) (cadr binding))
|
|
|
|
|
|
|
|
|
|
(define (make-combination operator operands) (cons operator operands))
|
|
|
|
|
|
|
|
|
|
(define (let->combination exp)
|
|
|
|
|
;;make-combination defined in earlier exercise
|
|
|
|
|
(let ((bindings (let-bindings exp)))
|
|
|
|
|
(make-combination (make-lambda (map let-var bindings)
|
|
|
|
|
(let-body exp))
|
|
|
|
|
(map let-val bindings))))
|
2023-11-04 21:16:20 +00:00
|
|
|
|
|
|
|
|
|
(define (amb-eval-program-in-env program env)
|
|
|
|
|
(eval-program program
|
|
|
|
|
(lambda (exp env)
|
|
|
|
|
(ambeval exp
|
|
|
|
|
env
|
|
|
|
|
(lambda (value fail) value)
|
|
|
|
|
(lambda () 'failed)))
|
|
|
|
|
user-print
|
|
|
|
|
env))
|
|
|
|
|
|
|
|
|
|
(define (amb-eval-program program)
|
|
|
|
|
(define env (setup-environment))
|
|
|
|
|
(amb-eval-program-in-env amb-utilities-program env)
|
|
|
|
|
(amb-eval-program-in-env program env))
|
2023-10-19 22:01:00 +00:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
'AMB-EVALUATOR-LOADED
|