How To Make Determinations at Clojure Macro Expansion Time - clojure

I believe I understand that during macro expansion, a macro does not have access to the things a function has access to, because expansion happens before compile time.
But, I am having trouble understanding is how to perform checks at macro expansion time.
For example:
(defn gen-class [cl-nam]
(fn [cmd & args]
(condp = cmd
:name (name cl-nam))))
(defmacro defnclass [cl-nam]
`(def ~cl-nam (gen-class '~cl-nam)))
I would like to check to see that cl-nam is not a sequence. I would like to use count and find out of its length is > 1.
I understand I can unquote the println in the following macro, so that I can get an expansion-time message.
(defmacro defnclass_info [cl-nam]
`(do
~(println cl-nam)
(def ~cl-nam (gen-class '~cl-nam))))
But, I am not sure how to go about checking to see what was passed for cl-nam.
I'm reading a lot of Clojure macro descriptions from several books, and am stumped.
Thanks.

A macro is really just a function.
(defmacro defnclass-info
[cl-name]
(when (seq? cl-name)
(throw (Exception. "cl-name must not be a sequence")))
`(def ~cl-name (gen-class '~cl-name)))
Edit: One could also switch behaviour and recursively call the macro again for the whole list. What you do, depends on your requirements.
(defmacro defnclass-info
[cl-name]
(if (seq? cl-name)
`(do ~#(for [cn cl-name] `(defnclass-info ~cn)))
`(def ~cl-name (gen-class '~cl-name))))
The macro expansion is just what the "function" returns. So you have full flexibility on what you do with the macro arguments.

Related

Using let style destructuring for def

Is there a reasonable way to have multiple def statements happen with destructing the same way that let does it? For Example:
(let [[rtgs pcts] (->> (sort-by second row)
(apply map vector))]
.....)
What I want is something like:
(defs [rtgs pcts] (->> (sort-by second row)
(apply map vector)))
This comes up a lot in the REPL, notebooks and when debugging. Seriously feels like a missing feature so I'd like guidance on one of:
This exists already and I'm missing it
This is a bad idea because... (variable capture?, un-idiomatic?, Rich said so?)
It's just un-needed and I must be suffering from withdrawals from an evil language. (same as: don't mess up our language with your macros)
A super short experiment give me something like:
(defmacro def2 [[name1 name2] form]
`(let [[ret1# ret2#] ~form]
(do (def ~name1 ret1#)
(def ~name2 ret2#))))
And this works as in:
(def2 [three five] ((juxt dec inc) 4))
three ;; => 3
five ;; => 5
Of course and "industrial strength" version of that macro might be:
checking that number of names matches the number of inputs. (return from form)
recursive call to handle more names (can I do that in a macro like this?)
While I agree with Josh that you probably shouldn't have this running in production, I don't see any harm in having it as a convenience at the repl (in fact I think I'll copy this into my debug-repl kitchen-sink library).
I enjoy writing macros (although they're usually not needed) so I whipped up an implementation. It accepts any binding form, like in let.
(I wrote this specs-first, but if you're on clojure < 1.9.0-alpha17, you can just remove the spec stuff and it'll work the same.)
(ns macro-fun
(:require
[clojure.spec.alpha :as s]
[clojure.core.specs.alpha :as core-specs]))
(s/fdef syms-in-binding
:args (s/cat :b ::core-specs/binding-form)
:ret (s/coll-of simple-symbol? :kind vector?))
(defn syms-in-binding
"Returns a vector of all symbols in a binding form."
[b]
(letfn [(step [acc coll]
(reduce (fn [acc x]
(cond (coll? x) (step acc x)
(symbol? x) (conj acc x)
:else acc))
acc, coll))]
(if (symbol? b) [b] (step [] b))))
(s/fdef defs
:args (s/cat :binding ::core-specs/binding-form, :body any?))
(defmacro defs
"Like def, but can take a binding form instead of a symbol to
destructure the results of the body.
Doesn't support docstrings or other metadata."
[binding body]
`(let [~binding ~body]
~#(for [sym (syms-in-binding binding)]
`(def ~sym ~sym))))
;; Usage
(defs {:keys [foo bar]} {:foo 42 :bar 36})
foo ;=> 42
bar ;=> 36
(defs [a b [c d]] [1 2 [3 4]])
[a b c d] ;=> [1 2 3 4]
(defs baz 42)
baz ;=> 42
About your REPL-driven development comment:
I don't have any experience with Ipython, but I'll give a brief explanation of my REPL workflow and you can maybe comment about any comparisons/contrasts with Ipython.
I never use my repl like a terminal, inputting a command and waiting for a reply. My editor supports (emacs, but any clojure editor should do) putting the cursor at the end of any s-expression and sending that to the repl, "printing" the result after the cursor.
I usually have a comment block in the file where I start working, just typing whatever and evaluating it. Then, when I'm reasonably happy with a result, I pull it out of the "repl-area" and into the "real-code".
(ns stuff.core)
;; Real code is here.
;; I make sure that this part always basically works,
;; ie. doesn't blow up when I evaluate the whole file
(defn foo-fn [x]
,,,)
(comment
;; Random experiments.
;; I usually delete this when I'm done with a coding session,
;; but I copy some forms into tests.
;; Sometimes I leave it for posterity though,
;; if I think it explains something well.
(def some-data [,,,])
;; Trying out foo-fn, maybe copy this into a test when I'm done.
(foo-fn some-data)
;; Half-finished other stuff.
(defn bar-fn [x] ,,,)
(keys 42) ; I wonder what happens if...
)
You can see an example of this in the clojure core source code.
The number of defs that any piece of clojure will have will vary per project, but I'd say that in general, defs are not often the result of some computation, let alone the result of a computation that needs to be destructured. More often defs are the starting point for some later computation that will depend on this value.
Usually functions are better for computing a value; and if the computation is expensive, then you can memoize the function. If you feel you really need this functionality, then by all means, use your macro -- that's one of the sellings points of clojure, namely, extensibility! But in general, if you feel you need this construct, consider the possibility that you're relying too much on global state.
Just to give some real examples, I just referenced my main project at work, which is probably 2K-3K lines of clojure, in about 20 namespaces. We have about 20 defs, most of which are marked private and among them, none are actually computing anything. We have things like:
(def path-prefix "/some-path")
(def zk-conn (atom nil))
(def success? #{200})
(def compile* (clojure.core.memoize/ttl compiler {} ...)))
(def ^:private nashorn-factory (NashornScriptEngineFactory.))
(def ^:private read-json (comp json/read-str ... ))
Defining functions (using comp and memoize), enumerations, state via atom -- but no real computation.
So I'd say, based on your bullet points above, this falls somewhere between 2 and 3: it's definitely not a common use case that's needed (you're the first person I've ever heard who wants this, so it's uncommon to me anyway); and the reason it's uncommon is because of what I said above, i.e., it may be a code smell that indicates reliance on too much global state, and hence, would not be very idiomatic.
One litmus test I have for much of my code is: if I pull this function out of this namespace and paste it into another, does it still work? Removing dependencies on external vars allows for easier testing and more modular code. Sometimes we need it though, so see what your requirements are and proceed accordingly. Best of luck!

How do I pass a variadic macro to a function?

I am attempting to learn Clojure and am having trouble with macros. I have a simple macro:
(defmacro add [& x] `(apply + (list ~#x)))
and then I have a function that can call multiple operations (add, subtract, multiply, and divide). I get these from stdin but for simplicity I have created a variable holding a list of numbers:
(defn do-op
[op]
(def numbers (list 1 2 3))
(apply op numbers))
In order to call do-op with the appropriate operation I need to pass the macro to do-op in an anonymous function:
(do-op #(add %&))
When I run this code using arguments passed from stdin I get a confusing error:
Cannot cast clojure.lang.ChunkedCons to java.lang.Number
When I execute this in a REPL I get:
Cannot cast clojure.lang.PersistentList to java.lang.Number
I assume that this has something to do with my lack of understanding of how these variadic arguments are getting handled but I am thoroughly stumped. What am I missing?
You can never ever pass a macro as if it was a function, since it doesn't exist after the code is compiled and ready to run.
When you have;
(do-op #(add %&)) ; which is shorthand for
(do-op (fn [& rest] (add rest))) ; then you expand the macro
(do-op (fn [& rest] (apply + (list (UNQUOTE-SPLICE 'rest)))) ; how do you unsplice the symbol rest to be separate elements?
The short answer is that rest can never be unspliced and thus you are using the macro wrong. However it seems you are just making an alias for + and it can be done by making a function or just making a binding to the original:
(defn add [& args] (apply + args)) ; making a function that calls + with its arguments
(def add +) ; or just make a binding pointing to the same function as + points to
(do-op add) ; ==> 6
You should keep to using functions as abstraction. Whenever you need to write something very verbose, where you cannot make it a function because of too early evaluation, then you have a candidate for a macro. It then translates a shorter way to write it with the long verbose way to write it without knowing the actual data types behind the variable symbols, since the compiler won't know what they are when expanding the macro. Also a macro gets expanded once, while the function that had the macro might get executed many times.
EDIT
In your pastebin code I can confirm you never ever need a macro:
(cond
(= 1 option) (do-op #(add %&))
...)
Should just be
(cond
(= 1 option) (do-op +)
...)
No need to wrap or make macro for this. Pass the function as is and it will do what you want.
Macros run at compile time and transform code data, not runtime data.
There is simply no way to generically apply to a macro a form evaluating to a sequence (like the symbol numbers) because it needs be to evaluated first, which can only happen at runtime (after compile time).
This is the full answer. Hopefully it helps you along understanding macros in Clojure.
If I understand what you are thinking, you should do it more like this:
(ns clj.core
(:require
[tupelo.core :as t]
))
(t/refer-tupelo)
(defn add [& x]
(apply + x))
(def numbers [1 2 3] )
(defn do-op
[op]
(apply op numbers))
(spyx (do-op add))
(defn do-op-2
[op vals]
(apply op vals))
(spyx (do-op-2 add numbers))
to get result:
> lein run
(do-op add) => 6
(do-op-2 add numbers) => 6
Usually we try to avoid having functions access global values like numbers. With do-op-2 we pass the vector of numbers into the function instead.
Note: For (spyx ...) to work you're project.clj must include
:dependencies [
[tupelo "0.9.9"]
Update
Of course, you don't really need do-op, you could do:
(defn add-all [nums-vec]
(apply + nums-vec))
(spyx (add-all numbers))
;=> (add-all numbers) => 6

Clojure : Defining a forv macro using for

I'm trying to write my second macro but I'm completely stuck here.
I would like to avoid writing everytime (vec (for [...])) so I'm trying to write a forv macro like filterv, mapv, etc.
I work mostly with vectors in my programs since I need to have access to the index because I use external buffers/descriptors to fasten matrix process.
I have written many ***v like functions (also adaptative functions like fmap )but I'm sticked with for.
So I wrote
(defmacro forv
[seq-exprs body-expr]
(vec (for (vec seq-exprs) body-expr)))
I tried with seq-exprs alone, it does not work. To be honest I tried also ~ and so on but I do not know how it works, I succeed in my first macro because it was far easier.
Clojure tell me that for requires a vector for binding.
Can someone help me and also explain what I am missing ? Thanks !
You could use the one built into the Tupelo Library. Source code is here: https://github.com/cloojure/tupelo/blob/master/src/tupelo/core.cljc#L181
(defmacro forv
"Like clojure.core/for but returns results in a vector. Equivalent to (into [] (for ...)). Not
lazy."
[& body]
`(vec (for ~#body)))
;;
;; you want something like that in the end: (forv [x (range 2)] x) => (vec (for [x (range 2)] x))
;;
(defmacro forv
[seq-exprs body-expr]
`(vec (for [~#seq-exprs] ~body-expr)))
;;
;; check quote and unquote
;; in particular, check the tricky bit is https://clojuredocs.org/clojure.core/unquote-splicing
;;
Edit: I based my answer to mimic the original code in the question, but Alan's answer is better than mine.

Clojure macro as function / 'Partial' for Macros?

This is similar to the problem discussed in Treat Clojure macro as a function but when trying the approach in the top answer, I got an error. Hopefully too much information about my specific application is not necessary, because it is quite complicated, but here is a distilled version of what I tried to do:
(defmacro make-fn [m arg1]
`(fn [& args#]
(eval `(~'~m ~'~arg1 ~#args#))))
I used the macro in this context:
(let [columns (make-columns table-width)
table-name (keyword (str "table_" n))]
(apply (make-fn helpers/tbl table-name) columns))
"helpers/tbl" is a macro that expects a table name keyword and a variable number of lists containing column specifications (like [:varchar 100] or something). I am trying to create random database table specifications on the fly to facilitate some testing. Anyway, when trying to execute the above code, I get the following error:
CompilerException java.lang.RuntimeException: Unable to resolve symbol: table-name in this context, compiling:(NO_SOURCE_PATH:1)
I sort of grasp the problem: macro expansion is done at compile-time, and I am trying to include a runtime value in the macro expansion, hence the odd use of quoting and unquoting to get everything set up just right. I basically want a partial for macros, and I need to be able to reuse this mechanism for different macros in different namespaces, and have all of the variable resolution come out right. Is this even possible?
The problem is caused by the way Clojure resolves symbols within a syntax-quote (backtick) expression. To avoid unintentional variable capture, Clojure always interprets symbols within a syntax-quote expression as referring to Vars (not locals).
You can get around this by "rolling your own" form-building code, equivalent to that generated by syntax-quote. It's as ugly as sin, but it works... just don't say I didn't warn you:
(defmacro make-fn [m arg1]
(let [g (gensym)]
(list 'fn ['& g]
(list 'eval (list 'concat (list 'list m arg1) g)))))
Wow, this is like a flashback to my Common Lisp days...

Difference between using list and back tick in macros

At a conceptual level a macro in LISP (and dialects) take a piece of code (as list) and returns another piece of code (again as list).
Based on above principle a simple macro could be:
(defmacro zz [a] (list print a))
;macroexpand says : (#<core$print clojure.core$print#749436> "Hello")
But in clojure this can also be written as:
(defmacro zz [a] `(print ~a))
;macroexpand says : (clojure.core/print "Hello")
I am not exactly sure about the difference here and which should be the preferred way. The first one look simple as we are supposed to return list and avoid using weird characters like back tick.
No one has pointed this out yet...the difference between your 2 macros is this: your second form (using backtick)
(defmacro zz [a] `(print ~a))
is equivalent to:
(defmacro zz [a] (list 'print a))
Which is different from your first example:
(defmacro zz [a] (list print a))
Note the missing single quote -- that is why your macroexpand is different. I agree with the other people posting: using backquote is more conventional if your macro has a fairly simple 'shape'. If you have to do code walking or dynamic construction (i.e. a complex macro), then using lists and building it up is often what's done.
I hope this explanation makes sense.
Constructing lists explicitly is "simplest", in a way, because there are few core concepts you need to know: just accept a list and change it around till you have a new list. Backtick is a convenient shortcut for "templating" chunks of code; it is possible to write any macro without it, but for any large macro it quickly becomes very unpleasant. For example, consider two ways of writing let as a macro over fn:
(defmacro let [bindings & body]
(let [names (take-nth 2 bindings)
vals (take-nth 2 (rest bindings))]
`((fn [~#names]
(do ~#body))
~#vals)))
(defmacro let [bindings & body]
(let [names (take-nth 2 bindings)
vals (take-nth 2 (rest bindings))]
(cons (list `fn (vec names) (cons `do body))
vals)))
In the first case, using backtick makes it fairly clear that you're writing a function of the names containing the body, and then calling it with the values - the macro code is "shaped" the same as the expansion code, so you can imagine what it will look like.
In the second case, with just cons and list all over the place, it is a real headache to work out what the expansion will look like. This isn't always the case, of course: sometimes it can be clearer to write something without a backtick.
Another very important point was made by Kyle Burton: print is not the same as 'print! Your macro expansion should contain the symbol print, not its value (which is a function). Embedding objects (such as functions) in code is very fragile and only works by accident. So make sure your macros expand to code you could actually have written yourself, and let the evaluation system do the hard work - you could type in the symbol print, but you couldn't type in a pointer to the current value of the function print.
There's a style difference between them. Your example is very simple but in more complex macros the difference will be bigger.
For example the unless macro as defined in "The Joy of Clojure" book:
(defmacro unless [condition & body]
`(if (not ~condition)
(do ~#body)))
From the book:
Syntax-quote allows the following if-form to act as a sort of template for the expression
that any use of the macro become when it is expanded.
When creating a macro always choose the most readable and idiomatic style.
To contrast, the above code can equivalently be written like so:
(defmacro unless [condition & body]
(list 'if (list 'not condition)
(list* 'do body)))
In my experience they are equivalent. Though there may be some edge cases I'm not aware of.
#islon 's example can equivalently be written as:
To contrast, the above code can equivalently be written like so:
(defmacro unless [condition & body]
(list 'if (list 'not condition)
(list* 'do body)))