If I want to define a function that accepts an unknown number of args I can easily do something like this:
(defn foo
[& args]
args)
It returns a value of type clojure.lang.ArraySeq which contains the value given in the function.
In macro, using ~# is unquote-splicing, which flattens the argument given:
(defmacro foo
[bar & baz]
`(println ~#baz))
If I use the macro like this:
(foo "foo" 1 2 3 4)
It will print out 1 2 3 4. But, I want to get the args unflattened. Doing ~baz (without #) gives me an exception. Any idea how to do it?
If you macroexpand-1 the version using ~baz, the cause of the problem becomes apparent:
(macroexpand-1 '(foo "foo" 1 2 3 4)) ; NB. using ~baz in foo's body
;= (println (1 2 3 4))
; ^
So here we're attempting to call 1 as a function. (NB. this call takes place and the exception is thrown at run time.)
The right way to fix this depends on what you want to achieve. For example, you could pour the rest arg into a vector and print that:
(defmacro foo [bar & baz]
`(println ~(vec baz)))
A comment on Michał Marczyk's answer ...
You can also see what's happening by turning the macro into a function:
(defn foo [bar & baz]
`(println ~#baz))
=> (foo "foo" 1 2 3 4)
(clojure.core/println (1 2 3 4))
Syntax quoting, unquoting, and unquote splicing still work. Aha! Macros differ from functions in how they are invoked, not in what they do.
You can always do
(defmacro foo
[bar & baz]
`(println (list ~#baz)))
to construct a seq or
(defmacro foo
[bar & baz]
`(println [~#baz]))
to construct a vector.
Related
Is it possible to have autocompletion of defprotocol methods in Emacs?
An example:
(defprotocol Foo
(bar [this])
(baz [this])
(deftype Qux [a b c]
Foo
(bar [this] a)
(baz [this] b))
(bar (Qux. 1 2 3))
(baz (Qux. 1 2 3))
I was looking for something like this(in pseudocode):
;; (1)
(`M-Tab` (Qux. 1 2 3))
;;
;; or (2):
(-> (Qux. 1 2 3) `M-Tab`)
to trigger a dropdown with bar & baz options.
As a workaround I'm currently using (2) but it needs to have at least 1st character to be present(autocomplete all options doesn't work).
Is there a better way to do it?
Thanks
For me auto-completion also works in case (1) when one character is present. It does not seem to specifically be aware of the functions belonging to the protocol, CIDER is just aware of the functions in scope. The completion-at-point does not seem to toggle without a first character. Maybe you can try asking on #cider of clojurians.slack.org?
😄
Given a simple function that returns one value, I can use define to bind its return value to a name
(define (foo) 1)
(define bar (foo))
however this doesn't seem to be possible when the function returns multiple values using values.
(define (baz) (values 2 3))
(define quux (baz))
; define-values: result arity mismatch;
; expected number of values not received
; expected: 1
; received: 2
; from:
; in: definition of quux
; values...:
; 2
; 3
I've looked through the docs, but the only thing related to values is let-values, which doesn't really apply here.
You want define-values, the definition equivalent to let-values.
(define (baz) (values 2 3))
(define-values (foo bar) (baz))
Problem: How to handle a catch-all parameter after & in a macro, when the arguments to be passed are sequences, and the catch-all variable needs to be dealt with as a sequence of sequences? What gets listed in the catch-all variable are literal expressions.
This is a macro that's intended to behave roughly Common Lisp's mapc, i.e. to do what Clojure's map does, but only for side-effects, and without laziness:
(defmacro domap [f & colls]
`(dotimes [i# (apply min (map count '(~#colls)))]
(apply ~f (map #(nth % i#) '(~#colls)))))
I've come to realize that this is not a good way to write domap--I got good advice about that in this question. However, I'm still wondering about the tricky macro problem that I encountered along the way.
This works if the collection is passed as a literal:
user=> (domap println [0 1 2])
0
1
2
nil
But doesn't work in other situations like this one:
user=> (domap println (range 3))
range
3
nil
Or this one:
user=> (def nums [0 1 2])
#'user/nums
user=> (domap println nums)
UnsupportedOperationException count not supported on this type: Symbol clojure.lang.RT.countFro (RT.java:556)
The problem is that it's literal expressions that are inside colls. This is why the macro domap works when passed a sequence of integers, but not in other situations. Notice the instances of '(nums):
user=> (pprint (macroexpand-1 '(domap println nums)))
(clojure.core/dotimes
[i__199__auto__
(clojure.core/apply
clojure.core/min
(clojure.core/map clojure.core/count '(nums)))]
(clojure.core/apply
println
(clojure.core/map
(fn*
[p1__198__200__auto__]
(clojure.core/nth p1__198__200__auto__ i__199__auto__))
'(nums))))
I've tried various combinations of ~, ~#, ', let with var#, etc. Nothing's worked. Maybe it's a mistake to try to write this as a macro, but I'd still be curious how to write a variadic macro that takes complex arguments like these.
Here is why your macro does not work:
'(~#colls) This expression creates a quoted list of all colls. E. g. if you pass it (range 3), this expression becomes '((range 3)), so the literal argument will be one of your colls, preventing evaluation of (range 3) certainly not what you want here.
Now if you would not quote (~#colls) inside the macro, of course they would become a literal function invocation like ((range 3)), which makes the compiler throw after macroexpansion time (it will try to eval ((0 1 2))).
You can use list to avoid this problem:
(defmacro domap [f & colls]
`(dotimes [i# (apply min (map count (list ~#colls)))]
(apply ~f (map #(nth % i#) (list ~#colls)))))
=> (domap println (range 3))
0
1
2
However one thing here is terrible: Inside the macro, the entire list is created twice. Here is how we could avoid that:
(defmacro domap [f & colls]
`(let [colls# (list ~#colls)]
(dotimes [i# (apply min (map count colls#))]
(apply ~f (map #(nth % i#) colls#)))))
The colls are not the only thing that we need to prevent from being evaluated multiple times. If the user passes something like (fn [& args] ...) as f, that lambda would also be compiled in every step.
Now this is the exactly the scenario where you should ask yourself why you are writing a macro. Essentially, your macro has to make sure all arguments are eval'd without transforming them in any way before. Evaluation comes gratis with functions, so let's write it as a function instead:
(defn domap [f & colls]
(dotimes [i (apply min (map count colls))]
(apply f (map #(nth % i) colls))))
Given what you want to achieve, notice there is a function to solve that already, dorun which simply realizes a seq but does not retain the head. E. g.:
`(dorun (map println (range 3)))
would do the trick as well.
Now that you have dorun and map, you can simply compose them using comp to achieve your goal:
(def domap (comp dorun map))
=> (domap println (range 3) (range 10) (range 3))
0 0 0
1 1 1
2 2 2
I want to make a macro which defines a function outside of the local variable scope, as to catch errors where the programmer (aka me) is incorrectly referencing variables in the local scope. It should only allow variables declared in the first argument of the macro.
For example, the following should compile fine:
(let [ foo 'x
bar 'y ]
(my-macro [ foo ] ;; this designates that foo can be used
(print foo)
)
)
but, the following should fail to compile, because "bar" wasn't declared in the first argument of my-macro:
(let [ foo 'x
bar 'y ]
(my-macro [ foo ] ;; only foo is declared here, but bar
;; is used, so should fail to compile
(print foo)
(print bar) ;; <-- should fail here
)
)
Besides the error checking, the macro needs to return a vector of the values of the variables used and a function containing the body. This is what I have so far.
(defmacro my-macro
[ declared-vars-in-use & body ]
`[~declared-vars-in-use (fn [~#declared-vars-in-use]
~#body
)
]
)
The only thing I don't know how to do is enforce the compilation error when referencing a symbol from the local scope that isn't declared in my-macro ("bar" in the above example). Forgive me if I'm using incorrect terms, and hopefully you can understand this, I am still a newbie at clojure.
(Updated with a version of explicit-closure free from the considerable limitations of the original approach.)
The macro below returns a function which closes over the specified locals and accepts specified additional arguments. If you only want a function which doesn't close over any locals at all (in other words, whose body only uses no external locals), which is what my-macro would produce if given the desired ability to prevent access to locals not on the declared-vars-in-use list (as the locals on the list would be shadowed by the parameters), you can simply eval an appropriate fn form, as eval ignores locals. (So, skip close-over and the let around the inner list* in the snippet below.)
(defmacro explicit-closure [close-over params & body]
(eval (list 'let
(vec (interleave close-over (repeat nil)))
(list* 'fn params body)))
`[~close-over (fn [~#params] ~#body)])
Note that the call to eval here happens during compilation and is only meant to coax the compiler into complaining if the function body references the wrong locals. If the body does not use disallowed locals or otherwise cause the eval call to fail, regular code for the function is emitted with no further checks or eval-induced compilation at runtime.
From the REPL:
(let [foo 1
bar 2]
(explicit-closure [foo] [x] (+ foo x)))
;= [[1] #<user$eval1887$fn__1888 user$eval1887$fn__1888#39c4d0cd>]
(let [foo 1
bar 2]
(let [[vals f] (explicit-closure [foo] [x] (+ foo x))]
(prn vals)
(f 3)))
;=> [1]
;= 4
;;; replace (+ foo x) with (+ foo bar x) in the above
;;; to get a CompilerException
I would like to have a macro which I'll call def-foo. Def-foo will create a function, and then will add this function to a set.
So I could call
(def-foo bar ...)
(def-foo baz ...)
And then there would be some set, e.g. all-foos, which I could call:
all-foos
=> #{bar, baz}
Essentially, I'm just trying to avoid repeating myself. I could of course define the functions in the normal way, (defn bar ...) and then write the set manually.
A better alternative, and simpler than the macro idea, would be to do:
(def foos #{(defn bar ...) (defn baz ...)} )
But I'm still curious as to whether there is a good way for the macro idea to work.
Do you want to end up with a set that has the names of functions in it (i.e. a set of Symbols), or a set containing vars (which resolve to functions)? If you want the former, you can add the symbols to an atom in the macro at compile-time, like Greg Harman's version.
If you want the latter, your macro must expand to code that does the atom-swapping after the function is defined. Remember that macros run at compile-time and the macro-expanded result runs at run-time; the function itself is not available until run-time.
(def all-foos (atom #{}))
(defmacro def-foo [x]
`(let [var# (defn ~x [] (println "I am" '~x))]
(swap! all-foos conj var#)))
If you want to be able to call the functions in this set, for example, you need to use the latter version.
user> (def-foo foo)
#{#'user/foo}
user> (def-foo bar)
#{#'user/foo #'user/bar}
user> ((first #all-foos))
I am foo
nil
Have the macro add the name of the new function to your set before creating the function, like so:
(def *foos* (atom (hash-set)))
(defmacro def-foo [name]
(swap! *foos* conj name)
`(defn ~name
[]
(println "This is a foo!")))
Result:
user=> (def-foo bar)
#'user/bar
user=> (def-foo baz)
#'user/baz
user=> (bar)
This is a foo!
nil
user=> (baz)
This is a foo!
nil
user=> *foos*
#<Atom#186b11c: #{baz bar}>