(define t1 (make-new-table (list 'name 'email))) (set-car! (table-fields t1) 'nom) (set-cdr! t1 t1)
(define (length lst) (if (null? lst) 0 (+ 1 (length (cdr lst))))) (length t1)Explain why the evaluation of (length t1) never terminates.
Note that the primitive length procedure behaves differently:
The length primitive expects a list, but t1 is not a list since it does not end with null.> (length t1)
length: expects argument of type
; given #0=(1 . #0#)
(define (table-insert! table entry) (assert (= (length entry) (length (table-fields table)))) (set-car! table (append (table-entries table) (list entry))))This would be simpler, but less efficient since we have to create a new list and copy all of the table entries into it every time we add an entry to the table.
(define lst null)
(append! lst 3)
lst
(define (post-item! name description) (table-insert! items (list name description))) (define (insert-bid! bidder item amount) (table-insert! bids (list bidder item amount)))
the running time of append! is in Θ(n) where n is the number of elements in the first list, since it evaluates (last-pair x) and last-pair cdr's down the list. Hence, insert-bid! has running time in Θ(b) where b is the number of entries in the bids table.(define (last-pair x) (if (null? (cdr x)) x (last-pair (cdr x)))) (define (append! x y) (set-cdr! (last-pair x) y) x)
(define (find-field-number table field)
(find-element-number (table-fields table) field))
(define (table-select table field proc)
(make-table
(table-fields table)
(let ((fieldno (find-field-number table field)))
(filter
(lambda (x) (proc (get-nth x fieldno)))
(table-entries table)))))
If the number of fields is not constant, then we need to consider how the work required by find-field-number and get-nth scales with the selected field. Both procedures need to cdr down a list until the matching entry is found. Hence, they are Θ(m) where m is the number of elements in the input list. As it is used in table-select it is the number of fields in the table in both cases. Hence, the total work is in Θ(nf) where n is the number of entries in the table argument and f is the number of fields in the table argument.
One way to define get-highest-bid is to use quicksort to order all the bids by bit amount, and then select the first one:
(define (get-highest-bid item)
(let ((sortbids
(quicksort
(get-bids item)
(lambda (entry1 entry2)
(> (get-nth entry1 (find-field-number bids 'amount))
(get-nth entry2 (find-field-number bids 'amount))))))
(if (> (length sortbids) 0) (car sortbids) 0)))
Note how the definition uses let to avoid needing to evalute
the expensive bid finding code twice.
Another approach would be to add a zero-bid to the list so we don't need the special case:
(define (get-highest-bid item)
(car
(quicksort
(cons (list 'dummy-bidder item 0) (get-bids item))
(lambda (entry1 entry2)
(> (get-nth entry1 (find-field-number bids 'amount))
(get-nth entry2 (find-field-number bids 'amount)))))))
The sorting approach was used by most students, but it is quite
inefficient since we only care about finding the highest bid. We could
do this using find-best:
(define (get-highest-bid item)
(let ((fieldno (find-field-number bids 'amount)))
(find-best
(lambda (bid1 bid2)
(if (> (get-nth bid1 fieldno) (get-nth bid2 fieldno)) bid1 bid2))
(get-bids item))))
(define (place-bid bidder item amount)
(let ((bidder-entry (table-entries
(table-select bidders 'name
(make-string-selector bidder))))
(item-entry (table-entries
(table-select items 'item-name
(make-string-selector item)))))
(if (= (length bidder-entry) 0)
(printf "~a is not a legitimate bidder!" bidder)
(if (> (length bidder-entry) 1)
(printf "Multiple matching bidders: ~a" bidder-entry)
(if (= (length item-entry) 0)
(printf "The ~a is not for sale!" item)
(if (> (length item-entry) 1)
(printf "Multiple matching items: ~a" item-entry)
(let ((bidder-ent (car bidder-entry))
(item-ent (car item-entry)))
(let ((highest-bid (get-highest-bid item)))
(if (or (null? highest-bid)
(> amount
(get-nth highest-bid
(find-field-number bids 'amount))))
(begin
(printf "~a is now the high bidder for ~a: ~a"
bidder item amount)
(insert-bid! bidder item amount))
(printf "Bid amount does not exceed previous highest bid: ~a"
highest-bid))))))))))
(define (end-auction!)
(map
(lambda (item-entry)
(let ((item-name (get-nth item-entry (find-field-number items 'item-name))))
(let ((high-bid (get-highest-bid item-name)))
(if (zero? high-bid)
(printf "No bids on ~a.~n"
(get-nth item-entry
(find-field-number items 'item-name)))
(printf "Congratulations ~a! You have won the ~a for $~a.~n"
(get-nth high-bid (find-field-number bids 'bidder-name))
item-name
(get-nth high-bid (find-field-number bids 'amount)))))))
(table-entries items))
(void) ;; This makes end-auction! evaluate to no value, instead of the
;; list of #void's the map would evaluate to
This depends on the implementation we use. If we use the first definition from Question 7 the running time is in Θ(b log b):
(define (get-highest-bid item)
(let ((sortbids
(quicksort
(get-bids item)
(lambda (entry1 entry2)
(> (get-nth entry1 (find-field-number bids 'amount))
(get-nth entry2 (find-field-number bids 'amount)))))))
(if (> (length sortbids) 0)
(car sortbids)
0)))
The get-highest-bid evaluates (get-bids item). This
selects matching bids from the bids table. Since table-select
has running time in Θ(n) where n is the number of entries in the
table (question 6), this requires work in Θ(b). The length
of the resulting list is on average (/ b m)
since all bids are for items in the table. Then,
get-highest-bid evaluates (quicksort proc
(get-bids item)). The quicksort procedure has running time in
Θ(n log n) where n is the number of
elements in the input list (assuming the comparison function is constant
time, which it is in this case). Since the length of the input list is
b/m, the work required is in Θ(b/m log b/m). But,
get-highest-bid has to do both the work of get-bids
and then the quicksort, so its total work is in Θ(b + b/m log b/m).
Evaluating end-auction! evaluates get-highest-bid once for each item, so the total work is in: Θ(mb + blog b/m) On the other hand, if the more efficient get-highest-bid procedure were used, it requires work in Θ(b + b/m) since there is no sorting done. Then, the total running time is in: Θ(mb + b) = Θ(mb).