Exercise 4.51. Implement a new kind of assignment called permanent-set! that is not undone upon failure. For example, we can choose two distinct elements from a list and count the number of trials required to make a successful choice as follows: (define count 0) (let ((x (an-element-of '(a b c))) (y (an-element-of '(a b c)))) (permanent-set! count (+ count 1)) (require (not (eq? x y))) (list x y count)) ;;; Starting a new problem ;;; Amb-Eval value: (a b 2) ;;; Amb-Eval input: try-again ;;; Amb-Eval value: (a c 3) What values would have been displayed if we had used set! here rather than permanent-set! ? ———————————————————————————————————————————————————————————————————————— If set! was used, the displayed count will always be 1, since the computation will be rolled back to the beginning, where count is 0, before each additional result is found. We can implement permanent-set! more simply than set!, which goes to some trouble to undo the assignment while propagating failure. The result comes out much like analyze-definition. (define (analyze-permanent-assignment exp) (let ((var (permanent-assignment-var exp)) (vproc (analyze (permanent-assignment-value exp)))) (lamdba (env succeed fail) (vproc env (lambda (val fail2) (set-variable-value! var val) (succeed 'ok fail2)) fail))))