(define prices (list (cons 'coke 100) (cons 'fanta 100) (cons 'karamalz 120) (cons 'black-bush 250))) (define inventory (list (cons 'coke 300) (cons 'fanta 100) (cons 'karamalz 200) (cons 'black-bush 100))) (define drink-machine (lambda (prices inventory) (display-inventory inventory) (if (empty? inventory) (announce-the-end) (let ((order (accept-order))) (if (order-satisfiable? order inventory) (begin (confirm-order order) (let* ((price (order-price order prices)) (payment (accept-payment price))) (display-change price payment)) (drink-machine prices (apply-order order inventory))) (begin (display-rejection order inventory) (drink-machine prices inventory))))))) (define display-inventory (lambda (inventory) (display "The inventory: ") (newline) (for-each (lambda (inventory-entry) (display "drink: ") (display (car inventory-entry)) (display " stock: ") (display (cdr inventory-entry)) (newline)) inventory))) (define empty? (lambda (inventory) (every? (lambda (inventory-entry) (= 0 (cdr inventory-entry))) inventory))) (define announce-the-end (lambda () (display "I need a drink, too.") (newline))) (define accept-order (lambda () (let* ((product (prompt "What drink?")) (number (prompt "How many cans?"))) (cons product number)))) (define prompt (lambda (prompt-string) (display prompt-string) (newline) (read))) (define order-satisfiable? (lambda (order inventory) (let* ((requested-drink (car order)) (requested-number-of-cans (cdr order)) (number-of-cans (inventory-number-of-cans requested-drink inventory))) (<= requested-number-of-cans number-of-cans)))) (define inventory-number-of-cans (lambda (drink inventory) (cdr (any (lambda (inventory-entry) (equal? drink (car inventory-entry))) inventory)))) (define order-price (lambda (order prices) (let* ((drink (car order)) (price (drink-price drink prices)) (number-of-cans (cdr order))) (* number-of-cans price)))) (define drink-price (lambda (drink prices) (if (null? prices) (error "unfound drink") (if (equal? drink (car (car prices))) (cdr (car prices)) (drink-price drink (cdr prices)))))) (define accept-payment (lambda (price) (display "Insert ") (prompt price))) (define confirm-order (lambda (order) (display "You ordered ") (display (cdr order)) (display " cans of ") (display (car order)) (display ".") (newline))) (define display-change (lambda (price payment) (display "Here is your change: ") (display (- payment price)) (newline))) (define display-rejection (lambda (order inventory) (display "Sorry, we don't have enough ") (display (car order)) (display " in stock.") (newline))) (define apply-order (lambda (order inventory) (if (null? inventory) '() (let ((inventory-entry (car inventory))) (if (equal? (car order) (car inventory-entry)) (cons (cons (car order) (- (cdr inventory-entry) (cdr order))) (cdr inventory)) (cons inventory-entry (apply-order order (cdr inventory)))))))) (define any (lambda (proc? list) (if (null? list) #f (if (proc? (car list)) (car list) (any proc? (cdr list)))))) (define every? (lambda (proc? l) (fold-right (lambda (first result) (and result (proc? first))) #t l))) (define fold-right (lambda (proc unit l) (if (null? l) unit (proc (car l) (fold-right proc unit (cdr l))))))