Affordance and Concision
stuartsierra.com
stuartsierra.com
I tend to think of Lisp/Scheme logical and conditional operators taking an implicitly defined monad for the type of "useful value" or "nil" (#f in Scheme). It's just that:
1. You can't add new instances to the type class. 2. The language doesn't check you handle the failure case.
If there was a monad type class you could create a type "useful value" or "exception" (called Validation or Either in Haskell and Scala) and have the same concise code. However, without a static type system this kind of system just gets unmanageable (I know, I've tried it).
Proponents of dynamic typing often wax lyrical about the benefits of escaping the straight-jacket of static typing. They often don't appreciate the kinds of programs that are impossible to write without a modern type system. NB: this post is not one of them.
(defn get-or-throw [m k]
(or
(get m k)
(throw (RuntimeException. (str "could't find key " k " in map " m)))))
I understand most people use the simpler (key map) or (map key) forms instead of get, but at least you have an option. user> (get-or-throw {:k nil} :k)
RuntimeException could't find key :k in map {:k nil} user/get-or-throw (NO_SOURCE_FILE:4)