;; A Queue is a (Msg -> Procedure) ;; where Msg is one of: ;; - 'snoc => (Self * Value -> Queue) ;; - 'is-empty => (Self -> Bool) ;; - 'head => (Self -> Value) ;; - 'tail => (Self -> Queue) ;; ;; plus the abstract methods that Collection needs implemented: ;; - 'is-empty ;; - 'add-elem ;; - 'some-elem (define empty 'constructor-defined-below) (define snoc (lambda (q v) ((q 'snoc) q v))) (define isEmpty (lambda (q) ((q 'is-empty) q))) (define head (lambda (q) ((q 'head) q))) (define tail (lambda (q) ((q 'tail) q))) ;; We're going to need some stuff defined in here: (load "collection-delegate.scm") (letrec ((concrete->object ;; Listof[SchemeValue] -> Queue (lambda (lst) ;; Our "superclass" is Collection, so make one to handle ;; any messages we don't know about. (let ((super (base-collection))) (lambda (sym) (cond ;; These are the standard Queue messages, just cut-and-pasted ;; from queue1-dispatch.scm, and then added a self parameter ;; to each one. ((eq? sym 'snoc) (lambda (self val) (concrete->object (append lst (list val))))) ((eq? sym 'is-empty) (lambda (self) (null? lst))) ((eq? sym 'head) (lambda (self) (car lst))) ((eq? sym 'tail) (lambda (self) (concrete->object (cdr lst)))) ;; These are the "abstract methods" that we are responsible ;; for implementing if we want to claim to be a concretely ;; implemented subclass of Collection. ;; This code "links" the messages that Collection supports ;; to the methods that we've already defined for Queue ((eq? sym 'add-elem) (lambda (self val) (snoc self val))) ((eq? sym 'some-elem) (lambda (self) (list (head self) (tail self)))) ;; The is-empty message is handled above; we got ;; lucky. (Food for thought: what if interface for ;; Collection's is-empty did not match Queue's?) (else ;; For any other messages we pass the buck up to (super sym) ;; superclass; ask it what it wants to do here. ))))))) (set! empty (lambda () (concrete->object '()))))