`tokenize` function looks weird. Why use replace and then split? How would you extend this to stirngs (which might contain "()" chars)?
It might be OK in a toy example, but it would have been better if the author wrote an actual Reader (not familiar with Rust, but I guess it should have some readers that allow peeking 1 char ahead OR something like Java's PushbackReader).
Then `parse_list_of_floats`, if I am reading it right, this function is fail-safe, not fail-fast, right? It won't panic upon the very first reading error?
Why eval makes environment lookups? Shouldn't environment itself know how to perform a lookup?