Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why don't anonymous functions work with maps in clojure? [duplicate]

Tags:

maps

clojure

When I do the following it works:

user> (#(+ % 8) 7)
15

But why doesn't this work?

user> (#({:a %}) 7)
Execution error (ArityException) at user/eval74597$fn (form-init937950372947324749.clj:760).
Wrong number of args (0) passed to: clojure.lang.PersistentArrayMap

Expected result: {:a 7}

like image 552
zengod Avatar asked Mar 17 '26 07:03

zengod


2 Answers

Anon-fn with #() are a reader macro. If you look at the code generated, it becomes obvious, why it does not work (the body is called):

user=> '#({:a %})
(fn* [p1__8266#] ({:a p1__8266#}))

So the arg is passed as key for one map and it's called at once, since that is what the reader macro does. The usually safe way around this is using do, when you want to use the data literals:

user=> (#(do {:a %}) 7)
{:a 7}

Or, of course, using the various functions like hash-map to create the data structure.

like image 189
cfrick Avatar answered Mar 19 '26 22:03

cfrick


This is because the way the anonymous function shorthand expands, which on a clojure.lang.PersistentArrayMap happens to be invalid.

The #(+ % 8) shorthand is a macro that expands to:

(fn* [x] (+ x 8))

When you call it with #({:a %}) it expands to:

(fn* [x] ({:a x}))

Which tries to invoke the map as a function without its required arguments. Alternatively you can use assoc to achieve the desired result:

user=> (#(assoc {} :a %) 7)
{:a 7}
like image 41
pauldub Avatar answered Mar 19 '26 23:03

pauldub