#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"))