UNB/ CS/ David Bremner/ teaching/ cs4613/ tutorials/ tutorial06/ skeleton.rkt
#lang typed/racket
(require (rename-in typed/rackunit [check-equal? test])
         (only-in typed/rackunit check-exn))
(define-syntax-rule (test/exn expr msg)
  (check-exn exn:fail? (lambda () expr) msg))

(define (msg0 [obj : Node] [selector : Symbol]) (obj selector))

(define (node [v : Number] [l : Node] [r : Node]) : Node
  (lambda (m)
    (case m
      [(value) v]
      [(left)  l]
      [(right) r]
      [(sum) (+ v (+ (msg-num l 'sum) (msg-num r 'sum)))]
      [else (error 'node (symbol->string m))])))

(define (mt)
  (lambda ([m : Symbol])
    (case m
      [(sum) 0]
      [else (error 'mt (symbol->string m))])))

(define (msg-num obj selector) -1)
(define (msg-node obj selector) (mt))

(module+ test
  (define tree1 (node 1 (mt) (mt)))
  (test (msg0 tree1 'sum) 1)
  (test (msg0 tree1 'value) 1)
  (define tree2 (node 1 (node 2 (mt) (mt)) (mt)))
  (test (msg0 tree2 'value) 1)
  (test (msg0 (msg-node tree2 'left) 'value) 2)
  (test (msg0 (msg-node tree2 'right) 'sum) 0)
  (test/exn (msg0 (mt) 'left) "left")
  (test/exn (msg0 tree2 'wrong) "wrong")
  (test/exn (msg-num tree2 'left) "number")
  (test/exn (msg-node tree2 'value) "node"))