;; solutions to in-class script-position exercises ;;;; The define-script macro ;;;;;;;;;;;;;;;;;;;;;;;; (define abort #f) (let/cc grab-abort (set! abort grab-abort)) (define-syntax define-script (syntax-rules () [(define-script (script-name arg ...) body) (define (script-name arg ...) (abort body))])) (define (prompt-read s) (begin (printf s) (read))) (define (prompt-read-script s a) (begin (printf s) (a (read)))) ;;;;; the original voter program ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; age-page-nonweb : -> void ;; displays ability to vote based on user's age (define (age-page-nonweb) (let [(age (prompt-read "Enter your age: "))] (cond [(>= age 18) (printf "Don't forget to vote!")] [else (printf "You'll be able to vote in ~a years" (- 18 age))]))) (define-script (age-page2) (prompt-read-script "Enter your age: " (lambda (hole) (let [(age hole)] (cond [(>= age 18) (printf "Don't forget to vote!")] [else (printf "You'll be able to vote in ~a years" (- 18 age))]))))) ;;;;;;;; the adder revisited ;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (define (clean-adder) (printf "sum: ~a~n" (+ (prompt-read "Enter the first number: ") (prompt-read "Enter the second number: ")))) (define (clean-adder2) (prompt-read-script "Enter the first number: " (lambda (hole1) (prompt-read-script "Enter the second number: " (lambda (hole2) (printf "sum: ~a~n" (+ hole1 hole2))))))) ;;;;;;;; the tip calculator ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (define (add-tip bill) (+ bill (* bill (/ (prompt-read "Enter tip percentage: ") 100)))) (define (tip-adder) (add-tip (prompt-read "Enter bill amount: "))) (define (add-tip2 bill) (prompt-read-script "Enter tip percentage: " (lambda (hole) (+ bill (* bill (/ hole 100)))))) (define (tip-adder2) (prompt-read-script "Enter bill amount: " add-tip2)) ;;;;;;;;; the fight instigator ;;;;;;;;;;;;;;;;;;;;;;;;;; (begin (prompt-read (format "In how many games should the ~a win the series? " (prompt-read "Who should win the World Series? "))) (printf "Dream on!~n")) (prompt-read-script "Who should win the World Series? " (lambda (hole1) (prompt-read-script (format "In how many games should the ~a win the series? " hole1) (lambda (hole2) (begin hole2 (printf "Dream on!~n")))))) ;;;;;; tallying inputs ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (define (tally item-list) (cond [(empty? item-list) 0] [else (+ (prompt-read (format "Enter cost for ~a" (first item-list))) (tally (rest item-list)))])) ;; the point here is that if you just move the call to prompt-read-script, ;; you don't get the same behavior as the original function. Once you ;; have a call to a script inside a recursive function, you hae to make ;; the recursive function a script as well. This example also reminds ;; you to call the action parameter on each cond answer. (define-script (tally/scr item-list action) (cond [(empty? item-list) (action 0)] [else (prompt-read-script (format "Enter cost for ~a" (first item-list)) (lambda (hole) (tally/scr (rest item-list) (lambda (hole2) (action (+ hole hole2))))))])) ;;;;; looping to update accounts ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; (define account (let ([balance 0]) (lambda () (begin (printf "Current balance: ~a; " balance) (set! balance (+ balance (prompt-read "Change by"))) (account))))) ;; Here, you need to remember to introduce another begin inside the ;; (lambda (hole) ...) since two statements remain to execute. You ;; don't need to move the final call to account because it is already ;; in script position. However, account/scr does need an action ;; parameter. Since the call to account/scr is already in script ;; position, we can reuse the old action rather than create a new one. (define account/scr (let ([balance 0]) (lambda (action) (begin (printf "Current balance: ~a; " balance) (prompt-read-script "Change by" (lambda (hole) (begin (set! balance (+ balance hole)) (account/scr action))))))))