Error defining anonymous function in Clojure - clojure

I'm going through the Joy of Clojure book and ran into the following series of errors in Ch. 2:
(def make-list0 #(list))
=> (var cursive-test.core/make-list0)
(make-list0)
IllegalStateException Attempting to call unbound fn: #'cursive-test.core/list clojure.lang.Var$Unbound.throwArity (Var.java:43)
(def make-list2 #(list %1 %2))
=> (var cursive-test.core/make-list2)
(make-list2 1 2)
IllegalStateException Attempting to call unbound fn: #'cursive-test.core/list clojure.lang.Var$Unbound.throwArity (Var.java:43)
(def make-list2+ #(list %1 %2 %&))
=> (var cursive-test.core/make-list2+)
(make-list2+ 1 2 3 4 5)
IllegalStateException Attempting to call unbound fn: #'cursive-test.core/list clojure.lang.Var$Unbound.throwArity (Var.java:43)
I'm not sure what is going on here. I'm using IntelliJ IDEA with the Cursive plugin. Any ideas?

Somehow you accidentally defined something called list in your own namespace, but didn't give it a value. One way you could accidentally do this would be to use a def inside a function, but never actually call that function:
(defn foo [x]
(def list x))
The solution is to not do that, and the easiest way to get back to normalcy is to restart your repl and reload the namespace once it no longer has this incorrect redefinition of list in it. If you can't find where you've defined it, note that reloading the namespace should also print a warning message telling you you're redefining list, which I think includes a line number, but I don't recall for sure.

Related

Clojure ring-cors/wrap-cors setup

I'm using ring-cors and trying to pass a cors-policy for the (wrap-cors) function. This is what my code looks like:
(def cors-policy
{:access-control-allow-origin [#"http://localhost:8080"]
:access-control-allow-methods [:get :put :post]})
(def dev-handler (-> #'japi/routes
wrap-reload
wrap-params
(wrap-cors cors-policy) ;; <- Here
wrap-json-response
(wrap-defaults api-defaults)
push-state/handle))
This results in an error:
No value supplied for key: {:access-control-allow-origin
#{"http://localhost:8080"}, :access-control-allow-methods #{:get :post :put}}
Looking at the source code for (wrap-cors) it looks like the error is coming from trying to apply (hash-map) to my cors-policy map. It seems like I cannot pass a map definition but instead I have to pass the keys/values explicitly when calling (wrap-cors). Any ideas to work around this?
I've tried (apply hash-map cors-policy) in the repl and that works fine, however when passing a dummy handler such as (wrap-cors identity cors-policy) this again results in the same error.
Edit: cfrick's answer is correct, note however that I had to remove shadow-cljs' (push-state/handle) handler at the end of my dev-handler definition for my setup to work.
The wrapper uses a "pattern" that is sometimes seen and focuses on
"human consumption" of the function. It takes the "rest" of the
arguments and turns the pairs of it into a map. This is already "meh"
for humans and is utterly bad for machines (e.g. to pass as arguments).
You have to do the call it like this:
(wrap-cors $handler :a 1 :b 2)
So the easiest way from here would be:
(def cors-policy
[:a 1
:b 2])
(apply wrap-cors $handler cors-policy)
Or if you want to stick with the map (IMHO a good approach), you have to
flatten the map beforehand. e.g.
(apply wrap-cors $handler (into [] cat cors-policy))
But with the use of the threading macro -> this becomes harder to do
now (-> is just a macro and the resulting code would be (apply $handler wrap-cors ...) which is unintended.
So at this point I'd add my own defn that just takes the handler
again. E.g. something like
(defn cors-wrapper
[handler config-map]
(apply wrap-cors handler (into [] cat config-map)))

Increment a value in of an atom

I am learning clojurescript and i came across this snippet.
:on-click (fn [] (swap! state/order update (:id gig) inc))
I looked up the docs for update function and it said that update takes in a key and a functions. Passes the old value from the atom to the function and then update the atom. If there is no existing value for the key in atom nil is passed as input to the function.
When i tried the same thing in the repl it did not work
(def atom-test (atom {}))
(swap! atom-test update :aa inc)
NullPointerException clojure.lang.Numbers.ops (Numbers.java:1013)
Adding fnil to catch this NullPointerException worked.
user=> (swap! atom-test update :aa (fnil inc 0))
{:aa 1}
I cannot understand why it works in case 1 in clojurescript and why it does not work in case 2 in clojure repl. Can anyone explain whats the trick here.
For cljs, it is common for operations to safely handle nil without causing exceptions.
cljs.user=> (update {} :a inc)
{:a 1}
cljs.user=> (inc nil)
1
cljs.user=> (+ 1 nil)
1
https://cljs.github.io/api/syntax/nil
The inc function requires an argument that satisfies number?. This is true in Clojure and ClojureScript.
If you pass something else, like nil, the program is incorrect: (inc nil) has undefined behavior. This is not safe to do. It just so happens to return 1 but that is not guaranteed and is an accident of implementation.
If, for example, you instead pass a literal string to inc, ClojureScript will emit a warning at compile time:
cljs.user=> (inc "a")
WARNING: cljs.core/+, all arguments must be numbers, got [string number] instead at line 1 <cljs repl>
Perhaps in the future, the compiler could similarly emit a warning for (inc nil), but what is more likely to happen is that specs will be written covering core functions, with cljs.core/inc being specified to accept an argument satisfying number?.
TL;DR: using fnil is the correct thing to do here.

ClassCastException when calling Clojure function

I have written the following bit of code
(defn create [title url]
(when (not-any? clojure.string/blank? '(title url))
(println "doing stuff")))
However when I call the function
(create "title" "url")
I get the following error and cannot figure out what I am doing wrong
ClassCastException clojure.lang.Symbol cannot be cast to java.lang.CharSequence clojure.string/blank? (string.clj:279)
This is one of the things that also tripped me up when I first started learning clojure. Basically, you should use
(list title url)
The clojure compiler treats
'(title url)
as
(quote (title url))
'quote' does not evaluate anything inside of it, so 'title' and 'url' are just symbols (clojure.lang.Symbols to be precise).
Here's a better explanation than mine: http://blog.8thlight.com/colin-jones/2012/05/22/quoting-without-confusion.html

Unable to get random (doc) from a namespace

I want to display random (doc) page for some namespace.
The random function name I can get by:
user=> (rand-nth (keys (ns-publics 'clojure.core)))
unchecked-char
When I try to pass this to (doc) I get this:
user=> (doc (rand-nth (keys (ns-publics 'clojure.core))))
ClassCastException clojure.lang.PersistentList cannot be cast to clojure.lang.Symbol clojure.core/ns-resolve (core.clj:3883)
I'm new to Clojure and I'm not sure how to deal with this... I tried to convert this into regexp and use (find-doc) but maybe there is a better way to do this...
Explanation
The problem here is that doc is a macro, not a function. You can verify this with the source macro in the repl.
(source doc)
; (defmacro doc
; "Prints documentation for a var or special form given its name"
; {:added "1.0"}
; [name]
; (if-let [special-name ('{& fn catch try finally try} name)]
; (#'print-doc (#'special-doc special-name))
; (cond
; (special-doc-map name) `(#'print-doc (#'special-doc '~name))
; (resolve name) `(#'print-doc (meta (var ~name)))
; (find-ns name) `(#'print-doc (namespace-doc (find-ns '~name))))))
If you're new to Clojure (and lisps), you might not have encountered macros yet. As a devastatingly brief explanation, where functions operate on evaluated code, macros operate on unevaluated code - that is, source code itself.
This means that when you type
(doc (rand-nth (keys (ns-publics 'clojure.core))))
doc attempts to operate on the actual line of code - (rand-nth (keys (ns-publics 'clojure.core))) - rather than the evaluated result (the symbol this returns). Code being nothing more than a list in Clojure, this is why the error is telling you that a list can't be cast to a symbol.
Solution
So, what you really want to do is evaluate the code, then call doc on the result. We can do this by writing another macro which first evaluates the code you give it, then passes that to doc.
(defmacro eval-doc
[form]
(let [resulting-symbol (eval form)]
`(doc ~resulting-symbol)))
You can pass eval-doc arbitrary forms and it will evaluate them before passing them to doc. Now we're good to go.
(eval-doc (rand-nth (keys (ns-publics 'clojure.core))))
Edit:
While the above works well enough in the repl, if you're using ahead ahead-of-time compilation, you'll find that it produces the same result every time. This is because the resulting-symbol in the let statement is produced during the compilation phase. Compiling once ahead of time means that this value is baked into the .jar. What we really want to do is push the evaluation of doc to runtime. So, let's rewrite eval-doc as a function.
(defn eval-doc
[sym]
(eval `(doc ~sym)))
Simple as that.

In Clojure, how to define a variable named by a string?

Given a list of names for variables, I want to set those variables to an expression.
I tried this:
(doall (for [x ["a" "b" "c"]] (def (symbol x) 666)))
...but this yields the error
java.lang.Exception: First argument to def must be a Symbol
Can anyone show me the right way to accomplish this, please?
Clojure's "intern" function is for this purpose:
(doseq [x ["a" "b" "c"]]
(intern *ns* (symbol x) 666))
(doall (for [x ["a" "b" "c"]] (eval `(def ~(symbol x) 666))))
In response to your comment:
There are no macros involved here. eval is a function that takes a list and returns the result of executing that list as code. ` and ~ are shortcuts to create a partially-quoted list.
` means the contents of the following lists shall be quoted unless preceded by a ~
~ the following list is a function call that shall be executed, not quoted.
So ``(def ~(symbol x) 666)is the list containing the symboldef, followed by the result of executingsymbol xfollowed by the number of the beast. I could as well have written(eval (list 'def (symbol x) 666))` to achieve the same effect.
Updated to take Stuart Sierra's comment (mentioning clojure.core/intern) into account.
Using eval here is fine, but it may be interesting to know that it is not necessary, regardless of whether the Vars are known to exist already. In fact, if they are known to exist, then I think the alter-var-root solution below is cleaner; if they might not exist, then I wouldn't insist on my alternative proposition being much cleaner, but it seems to make for the shortest code (if we disregard the overhead of three lines for a function definition), so I'll just post it for your consideration.
If the Var is known to exist:
(alter-var-root (resolve (symbol "foo")) (constantly new-value))
So you could do
(dorun
(map #(-> %1 symbol resolve (alter-var-root %2))
["x" "y" "z"]
[value-for-x value-for-y value-for z]))
(If the same value was to be used for all Vars, you could use (repeat value) for the final argument to map or just put it in the anonymous function.)
If the Vars might need to be created, then you can actually write a function to do this (once again, I wouldn't necessarily claim this to be cleaner than eval, but anyway -- just for the interest of it):
(defn create-var
;; I used clojure.lang.Var/intern in the original answer,
;; but as Stuart Sierra has pointed out in a comment,
;; a Clojure built-in is available to accomplish the same
;; thing
([sym] (intern *ns* sym))
([sym val] (intern *ns* sym val)))
Note that if a Var turns out to have already been interned with the given name in the given namespace, then this changes nothing in the single argument case or just resets the Var to the given new value in the two argument case. With this, you can solve the original problem like so:
(dorun (map #(create-var (symbol %) 666) ["x" "y" "z"]))
Some additional examples:
user> (create-var 'bar (fn [_] :bar))
#'user/bar
user> (bar :foo)
:bar
user> (create-var 'baz)
#'user/baz
user> baz
; Evaluation aborted. ; java.lang.IllegalStateException:
; Var user/baz is unbound.
; It does exist, though!
;; if you really wanted to do things like this, you'd
;; actually use the clojure.contrib.with-ns/with-ns macro
user> (binding [*ns* (the-ns 'quux)]
(create-var 'foobar 5))
#'quux/foobar
user> quux/foobar
5
Evaluation rules for normal function calls are to evaluate all the items of the list, and call the first item in the list as a function with the rest of the items in the list as parameters.
But you can't make any assumptions about the evaluation rules for special forms or macros. A special form or the code produced by a macro call could evaluate all the arguments, or never evaluate them, or evaluate them multiple times, or evaluate some arguments and not others. def is a special form, and it doesn't evaluate its first argument. If it did, it couldn't work. Evaluating the foo in (def foo 123) would result in a "no such var 'foo'" error most of the time (if foo was already defined, you probably wouldn't be defining it yourself).
I'm not sure what you're using this for, but it doesn't seem very idiomatic. Using def anywhere but at the toplevel of your program usually means you're doing something wrong.
(Note: doall + for = doseq.)