1998 Spring
A <list-of-doors> is either
null, or
(cons d lod),
d is a <door>, and
lod is a <list-of-doors>.
;; lod-handler: <list-of-door> --> ?? ;; A template, following from the data definition. ;; ; (define lod-handler ; (lambda (lod) ; (cond [(null? lod) ...] ; [(cons? lod) ...(door-handler (first lod))... ; ...(lod-handler (rest lod))...])))Of course, you could have used
else instead
of asking cons?;
asking the question not only lets you re-order the cases with
impunity, but in real life lets you add an error clause,
[else (error 'lod-handler "Unexpected argument ~s~n" lod)].
define-structs.
A <door> is either
(make-room name), or
(make-hallway name lod), or
(make-outside),
name is a symbol
and lod is a <list-of-doors>.
To get these constructors constructors known to Scheme, we write
(define-struct room (name)) (define-struct hallway (name lod)) (define-struct outside ())For the last case we could have used a constant symbol (perhaps
'outdoors),
although it's perfectly fine to have a structure with zero fields.
The zero-argument structure is preferable because
outside? automatically,
and more importantly
;; door-handler:--> ?? ;; A template, following from the data definition. ;; ; (define door-handler ; (lambda (d) ; (cond [(room? d) ...(room-name d)] ; [(hallway? d) ...(hallway-name d)... ; ...(lod-handler (hallway-lod d))...] ; [(outside? d) ...] ; [else (error 'door-handler "Unknown type of door, ~s~n" d)])))
We flesh out the templates for <door> and <list-of-doors>.
A natural way to represent whether or not we can reach the outside
is by returning a boolean value.
(It is also acceptable to return tokens like
'can-get-out and 'locked-in.
Notice though that in Scheme, it is a convention that
functions whose names end in ? always return boolean.)
;; can-escape?:--> boolean ;; Does the door d lead to the outside? ;; (define door-handler (lambda (d) (cond [(room? d) #f] [(hallway? d) (hallway-leads-out? (hallway-lod d))] [(outside? d) #t] [else (error 'door-handler "Unknown type of door, ~s~n" d)])))
;; hallway-leads-out?: <list-of-doors> --> boolean
;; Can we get outside via any door in the hallway?
;;
(define hallway-leads-out?
(lambda (lod)
(cond [(null? lod) #f]
[(cons? lod) (or (door-handler (first lod))
(hallway-leads-out? (rest lod)))]
[else (error 'hallway-leads-out "bad list-of-doors ~s~n" lod)])))
A common bug was to not follow the template, and inside
the <list-of-doors> handler,
start dissecting the cases of the first door.
This usually resulted in a bug where if the first door were a hallway,
the answer just recurred on that hallway, ignoring all the rest of
the rooms in the original input list.