4

I wanted a function literal in Clojure that can take any number of arguments, but doesn't actually use them. So I've discovered %& ('rest arg' for function literal) and #_ ('discard' reader macro).

But how they work together surprises me:

=> (macroexpand `#(... #_ %&))
(fn* [& rest__125459__125460__auto__] (...))

This looks like what I wanted (and seems to work in the end), but is it how the discard macro supposed to work? The doc says:

The form following #_ is completely skipped by the reader.

But apparently here the ignored %& form has a side-effect, that is it affects the function literal args list. Should I rely on this behavior or does it look more like a bug?

alex
  • 925
  • 1
  • 7
  • 9

3 Answers3

3

The discard reader macro #_ is not intended to be used alone. Here you can see it in action:

Before:

(println "first")
(do
  (print "second ")
  (dotimes [i 5]
    (print i " "))
  (newline))
(println "third")

first
second 0  1  2  3  4  
third

and after:

(println "first")
#_(do
    (print "second ")
    (dotimes [i 5]
      (print i " "))
    (newline))
(println "third")

first
third

So adding #_ (recursively) discards everything inside the form it is applied to.

Regarding your original question of ignoring arguments, you have a few choices:

(mapv  #(do %& 42)        (range 3)) => [42 42 42]
(mapv   (fn [& _]   42)   (range 3)) => [42 42 42]
(mapv   (constantly 42)   (range 3)) => [42 42 42]
Alan Thompson
  • 29,276
  • 6
  • 41
  • 48
  • Thanks, I understand what is `#_` macro for and how it behaves normally. My question is specifically about combination of `#_ %&` and if the apparent side-effect was intended. Maybe I should reword the question subject a little. – alex Mar 17 '17 at 08:58
1

I spoke too soon, probably not a bug, maybe it should be disallowed and give an error. But really #_ is for discarding forms, and %& is not a form but also a reader macro.

So #_%& is just like #_@, #_; and doesn't work. The discard reader #_ is only to be used with "real forms" like () or [] (etc)

ClojureMostly
  • 4,652
  • 2
  • 22
  • 24
0

#_ clause is applied only to a form. In your example, there is a space after it so it doesn't have any effect.

Prepend any list/form with #_ to ignore it completely:

#_(do (print 42) (/ 0 0)) ;; there won't be an error

Ivan Grishaev
  • 1,583
  • 10
  • 15