#!r6rs
(library (obj-lecture tree-delegate)
(export leaf left right isLeaf nodeValue node)
(import (obj-lecture collection-delegate)
(rnrs base))
(define (leaf) (leaf->object)) (define (left t) ((t 'left) t))
(define (right t) ((t 'right) t))
(define (isLeaf t) ((t 'is-leaf) t))
(define (nodeValue t) ((t 'node-val) t))
(define (node t1 t2 val) ((t1 'make-node) t1 t2 val))
(define (abstract-tree)
(let ((super (base-collection)))
(lambda (sym)
(cond
((eq? sym 'is-empty) (lambda (self) (isLeaf self)))
((eq? sym 'add-elem) (lambda (self v)
(node self (leaf) v))) ((eq? sym 'some-elem)
(lambda (self)
(cond
((isLeaf self)
(error 'some-elem "cant-use-some-elem-on-empty-trees!"))
((isLeaf (left self)) (list (nodeValue self) (right self)))
((isLeaf (right self)) (list (nodeValue self) (left self)))
(else (let* ((val-and-rest (anyElem (left self)))
(lft-val (list-ref val-and-rest 0))
(lft-rest (list-ref val-and-rest 1)))
(list lft-val (node lft-rest
(right self)
(nodeValue self))))))))
(else (super sym) )))))
(define (node-fields->object lft rgt val)
(let ((super (abstract-tree)))
(lambda (sym)
(cond
((eq? sym 'is-leaf) (lambda (self) #f))
((eq? sym 'left) (lambda (self) lft))
((eq? sym 'right) (lambda (self) rgt))
((eq? sym 'node-val) (lambda (self) val))
((eq? sym 'make-node)
(lambda (self t2 val)
(node-fields->object self t2 val)))
(else (super sym)) ))))
(define (leaf->object)
(let ((super (abstract-tree)))
(lambda (sym)
(cond
((eq? sym 'is-leaf) (lambda (self) #t))
((eq? sym 'left) (lambda (self) (error 'left "I'm a leaf")))
((eq? sym 'right) (lambda (self) (error 'right "I'm a leaf")))
((eq? sym 'make-node)
(lambda (self t2 val)
(node-fields->object self t2 val)))
(else (super sym)) )))))