I need to look into Typed Racket more. Ever since I learned the tiny bit of Haskell that I know, I can't help but think that I need ADTs in my parenthesis.
Right at the top of the docs, though, it says that they designed the Typed Racket type system to provide static typing for existing untyped Racket programs. That makes me wonder what a statically typed lisp that wasn't trying to be backwards compatible would look like. I've heard of Shen and Qi but at first glance they (especially Qi) seemed to be drifting too far from Lispy prefix notation goodness for my taste.
> Hash tables make this sort of thing fairly easy though (at least in Racket)
It doesn't really help if you're trying to look up a string, though, because then you can't differentiate between a "good" string and an error string based on their types. That means it won't help for similar string fetching operations either, like making a network request and expecting either a response or a string indicating that the request timed out, the connection couldn't be made, etc.
According to the docs, you can also pass an error continuation to hash-ref instead of a failure string. That's interesting, though I have to admit I have trouble thinking in those terms.