Also ClojureScript has had accurate source mapping in Safari, Chrome, Firefox, and Node.js for quite a long time now and recently moved to support targets like iOS. It's a huge time saver even for an experienced Clojure programmer :)
I find it much simpler to deal with this style than with the equivalent in other languages, which would scatter the details across a half-dozen files, a dozen classes, and two dozen methods.
As far as spending more time reading Clojure than writing it I experience this myself - and I'm pretty sure this isn't a bad thing.
When I consider adopting a language, part of that consideration is how well I can read others' idiomatic code. It's so important for understanding libraries. I'm still just having a hard time with Clojure. I know it clicks for a lot of people though.
The problem with your let strategy is this can also impair readability if you use too many as the code becomes too far indented to the right (lets inside of lets inside of lets).
But I guess in these situations you can just use transients that are first defined to nil. Some people will probably yell at you for this.
In Common Lisp:
CL-USER 51 > (bake (make-instance 'pie :flavor :blackberry) 375 10.25)
Error: The value 3843.75 of #:|predicate1555| is not a predicate in CONDP.
1 (continue) Supply a new value of #:|predicate1555|.
2 (abort) Return to level 0.
3 Return to top loop level 0.
A clear error message and a way to repair it.A stack frame:
Call to BAKE {offset 394}
PIE : #<PIE 402000993B>
TEMP : 375
TIME : 10.25
DBG::|predicate| : 3843.75
DBG::|expression| : #<Function < 411007995C>
DBG::G : 3843.75 * (defun bake (pie temp time)
"Bakes a cake for a certain amount of time, returning a cake with a new
:tastiness level."
(setf (tastiness pie)
(condp (* temp time) #'<
(400 :burned)
(350 :perfect)
(300 :soggy))))
; in: DEFUN BAKE
; (CONDP (* TEMP TIME)
; #'<
; (400 :BURNED)
; (350 :PERFECT)
; (300 :SOGGY))
; ==>
; (LET ((#:PREDICATE2 (* TEMP TIME)) (#:EXPRESSION3 #'<))
; (DECLARE (TYPE FUNCTION #:PREDICATE2))
; (CHECK-TYPE #:PREDICATE2 FUNCTION "a predicate in CONDP")
; (COND ((FUNCALL #:PREDICATE2 #:EXPRESSION3 400) :BURNED)
; ((FUNCALL #:PREDICATE2 #:EXPRESSION3 350) :PERFECT)
; ((FUNCALL #:PREDICATE2 #:EXPRESSION3 300) :SOGGY)))
;
; caught WARNING:
; Derived type of (* TEMP TIME) is
; (VALUES NUMBER &OPTIONAL),
; conflicting with its asserted type
; FUNCTION.
; See also:
; The SBCL Manual, Node "Handling of Types"
;
; compilation unit finished
; caught 1 WARNING condition
Pretty cool...I apologize for being so shallow :)