#lang plait (define-type Exp [strE (v : String)] [numE (v : Number)] [prodE (l : Exp) (r : Exp)]) (define-type Value [numV (n : Number)] [strV (s : String)]) (define-type Type [numT] [strT]) (define (times n str) (if (zero? n) "" (string-append str (times (sub1 n) str)))) (define (interp slang) (type-case Exp slang [(strE s) (strV s)] [(numE n) (numV n)] [(prodE l r) (let ([l-v (interp l)] [r-v (interp r)]) (cond [(and (numV? l-v) (numV? r-v)) (numV (* (numV-n l-v) (numV-n r-v)))] [(numV? l-v) (strV (times (numV-n l-v) (strV-s r-v)))] [(numV? r-v) (strV (times (numV-n r-v) (strV-s l-v)))] [else (error 'interp "type mismatch")]))])) (test (interp (prodE (numE 6) (numE 7))) (numV 42)) (test (interp (prodE (numE 3) (strE "ha"))) (strV "hahaha")) (test (interp (prodE (numE 2) (prodE (numE 2) (strE "ha")))) (strV "hahahaha")) (test (interp (prodE (strE "hello") (numE 3))) (strV "hellohellohello")) (test/exn (interp (prodE (strE "hello") (strE "world"))) "mismatch") (define (typecheck exp) (type-case Exp exp [(strE v) (strT)] [(numE v) (numT)] [(prodE l r) (let ([lt (typecheck l)] [rt (typecheck r)]) (cond [(and (numT? lt) (numT? rt)) lt] [(numT? lt) rt] [(numT? rt) lt] [else (error 'typecheck "type mismatch")]))])) (test (typecheck (numE 6)) (numT)) (test (typecheck (strE "hello")) (strT)) (test (typecheck (prodE (numE 6) (numE 7))) (numT)) (test (typecheck (prodE (numE 3) (prodE (numE 6) (numE 7)))) (numT)) (test (typecheck (prodE (numE 3) (strE "ha"))) (strT)) (test (typecheck (prodE (strE "hello") (numE 3))) (strT)) (test (typecheck (prodE (prodE (numE 3) (numE 6)) (numE 7))) (numT)) (test/exn (typecheck (prodE (strE "hello") (strE "world"))) "mismatch") (test/exn (typecheck (prodE (prodE (numE 2) (strE "hello")) (strE "world"))) "mismatch") (test/exn (typecheck (prodE (prodE (numE 2) (strE "hello")) (prodE (strE "world") (numE 3)))) "mismatch") (test/exn (typecheck (prodE (strE "3") (prodE (numE 6) (strE "7")))) "mismatch") (test/exn (typecheck (prodE (strE "3") (prodE (strE "6") (strE "7")))) "mismatch")