This use of _
is purely conventional: from Clojure's point of view, it's just a regular symbol which can be used to name a local. So, you can simply check the value of _
directly to confirm your understanding:
(let [[x _ _ [y z]] v]
_)
;= 99.2
As for what goes on under the hood, the simplest way to check that is to macroexpand the let
form:
(macroexpand-1 '(let [[x _ _ [y z]] v] _))
The result of the above, reformatted for clarity, looks like this:
(let* [vec__7 v
x (clojure.core/nth vec__7 0 nil)
_ (clojure.core/nth vec__7 1 nil)
_ (clojure.core/nth vec__7 2 nil)
vec__8 (clojure.core/nth vec__7 3 nil)
y (clojure.core/nth vec__8 0 nil)
z (clojure.core/nth vec__8 1 nil)]
_)
So the second _
simply shadows the first one.
let*
is the implementation detail behind let
; it is a special form directly understood by the compiler, to which the let
macro adds destructuring support.