#lang plait
(define-type BinOp
[plus]
[++]) ;; string concat
(define-type Exp
[binE (operator : BinOp)
(left : Exp)
(right : Exp)]
[numE (value : Number)]
[strE (value : String)])
(define-type Type
[numT]
[strT])
(define (expect2 type lt rt)
(cond
[(and (equal? type lt) (equal? type rt)) type]
[else (type-case Type type
[(numT) (error 'tc "needs 2 numbers")]
[(strT) (error 'tc "needs 2 strings")])]))
(define (tc e)
(type-case Exp e
[(binE o l r)
(type-case BinOp o
[(plus) (expect2 (numT) (tc l) (tc r))]
[(++) (expect2 (strT) (tc l) (tc r))])]
[(numE v) (numT)]
[(strE v) (strT)]))
(test (tc (binE (plus) (numE 5) (numE 6))) (numT))
(test (tc (binE (++) (strE "hello") (strE "world"))) (strT))
(test/exn (tc (binE (++) (numE 5) (numE 6))) "strings")
(test/exn (tc (binE (plus) (strE "hello")
(strE "world"))) "numbers")