Consider the following macro:
(defmacro somemacro []
(list 'let ['somevar "Value"] 'somevar))
Expanding it yields the following result:
(macroexpand '(somemacro))
Result:
(let* [somevar "Value"] somevar)
I have two questions about let* (with the asterisk):
Unluckily I could not find any 'official' documentation about let*, that's why I'm asking here.
Sources I've already considered:
(doc let*) ; --> nil
(source let*) ; --> source not found
Nota Bene: let in Clojure is like let* in Scheme -- each init-expr has access to the preceding binding forms. (There is also a let*, but it is more or less let without destructuring, and in fact is the underlying implementation.)
In Clojure it basically means "foo* is like foo, but somehow different, and you probably want foo". In other words, it means that the author of that code couldn't come up with a better name for the second function, so they just slapped a star on it.
--> Is this the case for let and let*? But if so, still the question remains, what is exactly the difference?
Clojure let is used to define new variables in a local scope. These local variables give names to values. In Clojure, they cannot be re-assigned, so we call them immutable. Here are a few things you probably know about let , and a few you don't.
binding => var-symbol init-expr Creates new bindings for the (already-existing) vars, with the supplied initial values, executes the exprs in an implicit do, then re-establishes the bindings that existed before.
def is a special form that associates a symbol (x) in the current namespace with a value (7). This linkage is called a var . In most actual Clojure code, vars should refer to either a constant value or a function, but it's common to define and re-define them for convenience when working at the REPL.
let*
is an internal implementation detail. let
is a macro implemented in terms of let*
. https://github.com/clojure/clojure/blob/clojure-1.7.0/src/clj/clojure/core.clj#L4301
The macro let
adds parameter destructuring to let*
. This is the standard pattern for xyz
and xyz*
in Clojure, with the *
version not being documented. An exception being list
and list*
.
I thought I would add that the reason why macroexpand
returns let*
instead of let
can be found in the documentation of macroexpand
:
Repeatedly calls macroexpand-1 on form until it no longer represents a macro form, then returns it.
So what happens is the first call of macroexpand-1
returns (let [somevar "Value"] somevar)
, and the second expands let
into let*
.
Indeed,
user=> (println (clojure.string/join "\n" (take 3 (iterate macroexpand-1 '(somemacro)))))
(somemacro)
(let [somevar "Value"] somevar)
(let* [somevar "Value"] somevar)
nil
If you were to use destructuring in your macro, the output would be more interesting:
user=> (defmacro destructuring-macro [] `(let [[x y z] [:x :y :z]] y))
#'user/destructuring-macro
user=> (println (clojure.string/join "\n" (take 3 (iterate macroexpand-1 '(destructuring-macro)))))
(destructuring-macro)
(clojure.core/let [[testing.core/x testing.core/y testing.core/z] [:x :y :z]] testing.core/y)
(let* [vec__8356 [:x :y :z] x (clojure.core/nth vec__8356 0 nil) y (clojure.core/nth vec__8356 1 nil) z (clojure.core/nth vec__8356 2 nil)] testing.core/y)
nil
Notice that let
is fully qualified by the syntax quote, because it is not a special form (even though its documentation says it is). The underlying special form is let*
, which is not fully qualified by the syntax quote.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With