#lang racket/base
(require (only-in describe variant))
(define (type? object type-specifier)
(case (variant object)
((simple) (or (eq? 'simple type-specifier)
(cond ((number? object)
(or (eq? 'number type-specifier)
(if (real? object)
(or (eq? 'real type-specifier)
(if (exact? object)
(or (eq? 'exact type-specifier)
(and (integer? object)
(eq? 'integer type-specifier)))
(and (inexact? object)
(eq? 'inexact type-specifier))))
(and (complex? object)
(eq? 'complex type-specifier)))))
((null? object)
(eq? 'null type-specifier))
((char? object)
(eq? 'character type-specifier))
(else (and (boolean? object)
(eq? 'boolean type-specifier))))))
((pair) (or (eq? 'pair type-specifier)
(and (list? object)
(eq? 'list type-specifier))))
((type-specifier) #t)
(else #f)))
(define-syntax typecase
(syntax-rules (else)
((_ test-key
(else e1 ...))
(begin e1 ...))
((_ test-key
(type form ...))
(when (type? test-key 'type)
form ...))
((_ test-key
(type form ...) e1 ...)
(if (type? test-key 'type)
(begin form ...)
(typecase test-key
e1 ...)))))
I2xhbmcgcmFja2V0L2Jhc2UKCihyZXF1aXJlIChvbmx5LWluIGRlc2NyaWJlIHZhcmlhbnQpKQoKKGRlZmluZSAodHlwZT8gb2JqZWN0IHR5cGUtc3BlY2lmaWVyKQogIChjYXNlICh2YXJpYW50IG9iamVjdCkKICAgICgoc2ltcGxlKSAob3IgKGVxPyAnc2ltcGxlIHR5cGUtc3BlY2lmaWVyKQogICAgICAgICAgICAgICAgICAoY29uZCAoKG51bWJlcj8gb2JqZWN0KQogICAgICAgICAgICAgICAgICAgICAgICAgKG9yIChlcT8gJ251bWJlciB0eXBlLXNwZWNpZmllcikKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAoaWYgKHJlYWw/IG9iamVjdCkKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKG9yIChlcT8gJ3JlYWwgdHlwZS1zcGVjaWZpZXIpCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAoaWYgKGV4YWN0PyBvYmplY3QpCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKG9yIChlcT8gJ2V4YWN0IHR5cGUtc3BlY2lmaWVyKQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAoYW5kIChpbnRlZ2VyPyBvYmplY3QpCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKGVxPyAnaW50ZWdlciB0eXBlLXNwZWNpZmllcikpKQogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIChhbmQgKGluZXhhY3Q/IG9iamVjdCkKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIChlcT8gJ2luZXhhY3QgdHlwZS1zcGVjaWZpZXIpKSkpCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIChhbmQgKGNvbXBsZXg/IG9iamVjdCkKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAoZXE/ICdjb21wbGV4IHR5cGUtc3BlY2lmaWVyKSkpKSkKICAgICAgICAgICAgICAgICAgICAgICAgKChudWxsPyBvYmplY3QpCiAgICAgICAgICAgICAgICAgICAgICAgICAoZXE/ICdudWxsIHR5cGUtc3BlY2lmaWVyKSkKICAgICAgICAgICAgICAgICAgICAgICAgKChjaGFyPyBvYmplY3QpCiAgICAgICAgICAgICAgICAgICAgICAgICAoZXE/ICdjaGFyYWN0ZXIgdHlwZS1zcGVjaWZpZXIpKQogICAgICAgICAgICAgICAgICAgICAgICAoZWxzZSAoYW5kIChib29sZWFuPyBvYmplY3QpCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgKGVxPyAnYm9vbGVhbiB0eXBlLXNwZWNpZmllcikpKSkpKQogICAgKChwYWlyKSAob3IgKGVxPyAncGFpciB0eXBlLXNwZWNpZmllcikKICAgICAgICAgICAgICAgIChhbmQgKGxpc3Q/IG9iamVjdCkKICAgICAgICAgICAgICAgICAgICAgKGVxPyAnbGlzdCB0eXBlLXNwZWNpZmllcikpKSkKICAgICgodHlwZS1zcGVjaWZpZXIpICN0KQogICAgKGVsc2UgI2YpKSkKCihkZWZpbmUtc3ludGF4IHR5cGVjYXNlCiAgKHN5bnRheC1ydWxlcyAoZWxzZSkKICAgICgoXyB0ZXN0LWtleQogICAgICAgIChlbHNlIGUxIC4uLikpCiAgICAgKGJlZ2luIGUxIC4uLikpCiAgICAoKF8gdGVzdC1rZXkKICAgICAgICAodHlwZSBmb3JtIC4uLikpCiAgICAgKHdoZW4gKHR5cGU/IHRlc3Qta2V5ICd0eXBlKQogICAgICAgZm9ybSAuLi4pKQogICAgKChfIHRlc3Qta2V5CiAgICAgICAgKHR5cGUgZm9ybSAuLi4pIGUxIC4uLikKICAgICAoaWYgKHR5cGU/IHRlc3Qta2V5ICd0eXBlKQogICAgICAgICAoYmVnaW4gZm9ybSAuLi4pCiAgICAgICAgICh0eXBlY2FzZSB0ZXN0LWtleQogICAgICAgICAgICAgICAgICAgZTEgLi4uKSkpKSk=