UNB/ CS/ David Bremner/ teaching/ cs4613/ tutorials/ tutorial08/ skeleton.rkt
#lang plait
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Question 1 starts here
(define-type NodeOrNum
  [aNode .... ]
  [aNum (num : Number)])

(define-type-alias Node ....)

(define (msg-num [obj : Node] [selector : Symbol])
  ....)

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

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

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Question 2 starts here
(require (typed-in racket/base
                   [number->string : (Number -> String)]
                   [quotient : (Number Number -> Number)]))

(define MEMORY (make-vector 100 -1))
(define next-addr 0)
(define (reset) (set! next-addr 0))
(define (write-and-bump v)
  (let ([n next-addr])
    (begin
      (vector-set! MEMORY n v)
      (set! next-addr (add1 next-addr))
      n)))

(define NUMBER-TAG 2) ; 10 binary
(define BOOL-TAG 1) ; 01 binary

(define (ref->tag ref)
  (modulo ref 4))

(define (ref->word loc)
  (quotient loc 4))

(define (tag-word word tag)
  (+ tag (* 4 word)))

(define (store-num n)
  (tag-word (write-and-bump n) NUMBER-TAG))

(define (read-num a)
  (if (= (ref->tag a) NUMBER-TAG)
      (vector-ref MEMORY (ref->word a))
      (error 'number (number->string a))))

(define (store-bool b) ....)

(define (read-bool a) ....)

(define-type-alias Value Number)
(define numV store-num)
(define boolV store-bool)

(define-type Exp
  [numE (n : Number)]
  [boolE (b : Boolean)]
  [plusE (l : Exp) (r : Exp)]
  [ifE (c : Exp) (t : Exp) (e : Exp)])

(define (num+ la ra)
  (store-num (+ (read-num la) (read-num ra))))

(calc : (Exp -> Value))
(define (calc e)
  (type-case Exp e
    [(numE n) (numV n)]
    [(boolE b) (boolV b)]
    [(plusE l r) (num+ (calc l) (calc r))]
    [(ifE c t e) ....]))

(module+ test
  (test (read-num (calc (plusE (numE 1) (numE 2)))) 3)
  (test (read-num
         (calc (plusE (numE 1) (plusE (numE 2) (numE 3))))) 6)
  (test (read-bool (calc (boolE #t))) #t)
  (test (read-bool (calc (boolE #f))) #f)
  (test (read-num (calc (ifE (boolE #t) (numE 3) (plusE (numE 42) (boolE #f))))) 3)
  (test/exn (calc (ifE (boolE #f) (numE 3) (plusE (numE 42) (boolE #f)))) "number"))