I'm new in clojure, i try create functions thats will be sort collections and store it in object.
My code:
(defn uniq [ilist]
([] [])
(def sorted (sort ilist)))
I try to run it:
(uniq '(1,2,3,6,1,2,3))
but get error:
#<CompilerException java.lang.IllegalArgumentException: Key must be integer (NO_SOURCE_FILE:0)>
What's wrong?
Thank you.
As with your other question, you're trying to use pattern-matching where it just doesn't apply. Your function would work fine1 if you deleted the ([] []) entirely.
1 You also shouldn't use def here; as the other respondents have noted, you want to use let for establishing local bindings. However, here you don't need any bindings at all: just return the result of the sort call. In fact, the def will cause you to return a Var instead of the actual sorted list.
Since there's no need at all to use either 'let' or 'def', I have to agree with amalloy about Bart J's answer. Sure it warrants the upvotes because it's useful info, but it's not the right answer.
Actually, defining the function is kind of useless, since (sort ilist) would do the trick. The result of the function is the 'object' you want. That is, unless you want to use the result of the sort multiple times at different places in the function body. In that case, bind the result of sort to a function local variable.
If you only need the sort once, don't bother binding it at all, but just nest it inside other functions. For instance if you want to use it inside a unique function (which I guess is what you're wanting to do):
(defn uniq
"Get only unique values from a list"
[ilist]
; remove nils from list
(filter #(not(nil? %))
; the list of intermediate results from (reduce comppair sortedlist)
; (includes nils)
(reductions
; function to extract first and second from a list and compare
(fn comppair
[first second & rest]
(if (not= first second) second))
; the original sort list function
(sort ilist))))
(uniq '(1,2,3,6,1,2,3))
(1 2 3 6)
Then again, you could also just use the built-in distinct function, and take a look at it's source:
(distinct '(1,2,3,6,1,2,3))
(1 2 3 6)
(source distinct)
(defn distinct
"Returns a lazy sequence of the elements of coll with duplicates removed"
{:added "1.0"}
[coll]
(let [step (fn step [xs seen]
(lazy-seq
((fn [[f :as xs] seen]
(when-let [s (seq xs)]
(if (contains? seen f)
(recur (rest s) seen)
(cons f (step (rest s) (conj seen f))))))
xs seen)))]
(step coll #{})))
To store the sorted collection into a variable do this:
(let [sorted (sort your-collection)])
To understand the difference between a let and a def, this should help:
You can only use the lexical bindings made with let within the scope of let (the opening and closing parens). Let just creates a set of lexical bindings. def and let do pretty much the same thing. I use def for making a global binding and lets for binding something I want only in the scope of the let as it keeps things clean. They both have their uses.
Related
I'm studying Clojure, and I've read that in Clojure a function definition is just data, i.e. parameters vector is just an ordinary vector. If that's the case, why can I do this
(def add (fn [a b]
(+ a b)))
but not this
(def vector-of-symbols [a b])
?
I know I normally would have to escape symbols like this:
(def vector-of-symbols [`a `b])
but why don't I have to do it in fn/defn? I assume this is due to fn/defn being macros. I tried examining their source, but they are too advanced for me so far. My attempts to recreate defn also fail, and I'm not sure why (I took example from a tutorial):
(defmacro defn2 [name param & body]
`(def ~name (fn ~param ~#body)))
(defn2 add [a b] (+ a b)) ;;I get "Use of undeclared Var app.core/defn2"
Can someone please explain, how exactly does Clojure turn data structures, especially symbols, into code? And what am I missing about the macro example?
Update Apparently, macro does not work because my project is actually in Clojurescript (in Clojure it does work). I did not think it matters, but as I progress - I discover more and more things that somehow don't work for me in with Clojurescript.
Update 2 This helps: https://www.clojurescript.org/about/differences
A function is a first-class citizen as other data in Clojure.
To define a vector you use (vector ...) or reader has syntaxic sugar [...], for a list it's (list ...) or '(...) the quote not to evaluate the list as a function call, for a set (set ...) or #{...}.
So the factory function for a function is fn (in fact fn*, that comes from Java core of Clojure, fn is a series of macros to manage to destructure and all).
(fn args body)
is a function call that returns a function, where args is a vector of argument(s) event. empty and body is a series of Clojure expressions to be evaluated with args bind to the environment. If nothing is to be evaluated it returns nil. There is also a syntactic sugar #(...) with %x as argument x and % as argument 1.
(fn ...) return a value that is a function. So
(def my-super-function (fn [a b c d] (println "coucou") (+ a b c d)))
binds the symbol my-super-function with the anonymous function returned by (fn [a b c d] (println "coucou") (+ a b c d)).
(def my_vector [1 2 3])
binds the symbol my_vector with the vector [1 2 3]
List of learning resources: https://github.com/io-tupelo/clj-template#documentation
As #jas said, your defn2 macro looks fine.
The main point is that macros are an advanced feature that one almost never needs. A macro is equivalent to a compiler extension, and that is almost never the best solution to a problem. Also keep in mind that functions can do some things macros can't.
Another point: the syntax-quote (aka backquote) ` is very different from a single quote '. In your example you want the single quote for ['a 'b]. Even better would be to quote the entire vector form '[a b].
As to your primary question, it is poorly explained how source-file text is converted into code. This is a 2-step process. The Clojure Reader consumes text string data (from a file or a literal string) and produces data structures like lists, vectors, strings, numbers, symbols. The Clojure compiler takes these data structures as input and produces java byte code that can be executed.
It is confusing because, when printed, one can't tell the difference between the text representation of a vector [1 2 3] and the text string that is input to the reader [1 2 3]. Ideally it would be color-coded or something. This problem doesn't exist in Java, etc since they don't have macros and hence there is no confusion between the source code (text) and the data structures used by a macro (not text).
For a more detailed answer on creating macros in Clojure, please see this answer.
(defn recurse
[temp total] ;total is: (and true true(and false))
(map (fn [i]
(cond
(seq? i) (println "");If total is not a single parenthesis (single sequence), recur until it is
(= i 'and) (System/exit 0) ;I want this to be called only when the **second** "and" is called
:else (println "This should never print I think")
))
idealreturn)
)
I want (System/exit 0) to be called only when the second "and" is detected in total and not before. How would I go about doing this?
You are on the right track with mapping a function over the data to transform it. There are a couple of ways to get what you are looking for:
Don't use map, and use reduce instead. Reduce is for building up state over time. So you could reduce it into an expression, and each time you encounter an and, you look to see if there is already an and in the result you are building up, and if that and is already there, call the exit.
Have the function you are mapping over the input do only one thing, convert single items into more meaningful things. Then once it is done, pass that result to a second function that checks if it's time to exit.
Giving each thing one responsibility makes for code that's much easier to write, and composing them afterwords is efficient and easy. It's also much easier on you later when you come back to work on the code later.
I am trying to use a loop recur that creates an empty map inside the loop. For each entry in the loop (loops through a vector of maps) it will see if there is a key in the newly created map that matches the iterated values key and if not create one.
I have created this code:
(def meteor-map (json/read-str (clojure.string/lower-case
(slurp "https://data.nasa.gov/resource/y77d-th95.json"))))
(defn most-falls [values]
(loop [values map count-tracker{}]
(if (empty? values)
(count-tracker)
(do
(def key (keyword (get (first values) "year")))
(if (contains? (first values) key)
(do
(def count-tracker (update count-tracker key inc))
(recur (rest values) count-tracker)
)
(do
(def count-tracker (assoc count-tracker key 1))
(recur (rest values) count-tracker)
)
)
)
)
)
)
(most-falls meteor-map)
However when I call this function and pass in meteor-map (which is a vector of maps) i get an error saying
wrong number of args (0) passed to persistentarraymap
I think this could be due to how I am creating the initial count-tracker object inside the loop creation but I am unsure.
Any ideas?
Thanks
PS am aware this question is a bit vague so any questions just ask!
There's multiple things here to be brought up. Your main problem though is with (count-tracker). You're surrounding the map in parenthesis, which means that you want to call it as a function. You can't arbitrarily add parentheses to code like you can in other languages; it has a very specific meaning in Clojure. (f) always means that the function f is being called. Just change it to count-tracker to return the value.
Other things:
NEVER use def inside of a function unless it's necessary. In this case though, it's entirely unnecessary. Every use of def creates globals that last for the length of the program (yes, they exist even after the function exits!). Use let instead:
(let [key (keyword (get (first values) "year")))]
... ) ; Use key here
(loop [values map ...] will cause errors as well. map is a function, so this throws away the argument passed in to most-falls, overwriting it with the map function. This will cause an error when you try to use values as a sequence, since the map function doesn't support empty? or first, or anything else you're trying to use it for. I think you just intended to just rebind the argument to be used in the loop. Just change it to (loop [values values ...]. Arguably, you shouldn't shadow arguments by creating other bindings with the same name, but that's not exceedingly important here.
There's still a couple other petty things that could be improved. By using destructuring you could skip the calls to first and rest, and using reduce could simplify the explicit looping using loop, but those would detract from the main issues. Taking into consideration what I mentioned above, I'd write your function as:
(defn most-falls [values]
(loop [values values
count-tracker {}]
(if (empty? values)
count-tracker
(let [key (keyword (get (first values) "year"))]
(recur (rest values)
(if (contains? (first values) key)
(update count-tracker key inc)
(assoc count-tracker key 1)))))))
First, there is definitely an issue in that clause:
(loop [values map count-tracker{}]
I'm not use what did you try to achieve, but please take a look.
Next, never use def or defn forms inside the code, only on the top level of a namespace.
Finally, the loop/recur is pretty low-level form and should be used with a strong knowledge of what you are doing. More often, it might be replaced with more user-friendly ones. The reduce would be a good one I believe. It takes an initial value (an empty map in your case), a collection and a function of two arguments where the second one is the current collection's item and the second one either an initial value or a result of the previous function call.
Inside that function, you decide whether your map has some specific key and add it if it does not.
Short example:
# here are some data you've read from a file
(def items [{...} {...} {...}])
# reduce process function
(defn process
[result item]
(if (:some-key result) ;; here, you check the current map for a key
result ;; return the old map if everything is ok
(assoc result :some-key some-data))) ;; accumulate a new key into a map
(reduce process {} items)
There's something I don't understand about anonymous functions using the short notation #(..)
The following works:
REPL> ((fn [s] s) "Eh")
"Eh"
But this doesn't:
REPL> (#(%) "Eh")
This works:
REPL> (#(str %) "Eh")
"Eh"
What I don't understand is why (#(%) "Eh") doesn't work and at the same time I don't need to use str in ((fn [s] s) "Eh")
They're both anonymous functions and they both take, here, one parameter. Why does the shorthand notation need a function while the other notation doesn't?
#(...)
is shorthand for
(fn [arg1 arg2 ...] (...))
(where the number of argN depends on how many %N you have in the body). So when you write:
#(%)
it's translated to:
(fn [arg1] (arg1))
Notice that this is different from your first anonymous function, which is like:
(fn [arg1] arg1)
Your version returns arg1 as a value, the version that comes from expanding the shorthand tries to call it as a function. You get an error because a string is not a valid function.
Since the shorthand supplies a set of parentheses around the body, it can only be used to execute a single function call or special form.
As the other answers have already very nicely pointed out, the #(%) you posted actually expands to something like (fn [arg1] (arg1)), which is not at all the same as (fn [arg1] arg1).
#John Flatness pointed out that you can just use identity, but if you're looking for a way to write identity using the #(...) dispatch macro, you can do it like this:
#(-> %)
By combining the #(...) dispatch macro with the -> threading macro it gets expanded to something like (fn [arg1] (-> arg1)), which expands again to (fn [arg1] arg1), which is just want you wanted. I also find the -> and #(...) macro combo helpful for writing simple functions that return vectors, e.g.:
#(-> [%2 %1])
When you use #(...), you can imagine you're instead writing (fn [args] (...)), including the parentheses you started right after the pound.
So, your non-working example converts to:
((fn [s] (s)) "Eh")
which obviously doesn't work because the you're trying to call the string "Eh". Your example with str works because now your function is (str s) instead of (s). (identity s) would be the closer analogue to your first example, since it won't coerce to str.
It makes sense if you think about it, since other than this totally minimal example, every anonymous function is going to call something, so it'd be a little foolish to require another nested set of parens to actually make a call.
If you're in doubt what your anonymous function gets converted to, you can use the macroexpand procedure to get the representation. Remember to quote your expression before passing it to macroexpand. In this case we could do:
(macroexpand '#(%))
# => (fn* [p1__281#] (p1__281#))
This might print different names for p1__281# which are representations of the variables %.
You can also macroexpand the full invocation.
(macroexpand '(#(%) "Eh"))
# => ((fn* [p1__331#] (p1__331#)) "Eh")
Converted to more human readable by replacing the cryptic variable names by short names. We get what the accepted answers have reported.
# => ((fn* [s] (s)) "Eh")
Resources:
https://clojure.org/guides/weird_characters#_n_anonymous_function_arguments
https://clojuredocs.org/clojure.core/macroexpand
I am trying to determine whether a given argument within a macro is a function, something like
(defmacro call-special? [a b]
(if (ifn? a)
`(~a ~b)
`(-> ~b ~a)))
So that the following two calls would both generate "Hello World"
(call-special #(println % " World") "Hello")
(call-special (println " World") "Hello")
However, I can't figure out how to convert "a" into something that ifn? can understand. Any help is appreciated.
You might want to ask yourself why you want to define call-special? in this way. It doesn't seem particularly useful and doesn't even save you any typing - do you really need a macro to do this?
Having said that, if you are determined to make it work then one option would be to look inside a and see if it is a function definition:
(defmacro call-special? [a b]
(if (#{'fn 'fn*} (first a))
`(~a ~b)
`(-> ~b ~a)))
This works because #() function literals are expanded into a form as follows:
(macroexpand `#(println % " World"))
=> (fn* [p1__2609__2610__auto__]
(clojure.core/println p1__2609__2610__auto__ " World"))
I still think this solution is rather ugly and prone to failure once you start doing more complicated things (e.g. using nested macros to generate your functions)
First, a couple of points:
Macros are simply functions that receive as input [literals, symbols, or collections of literals and symbols], and output [literals, symbols, or collections of literals and symbols]. Arguments are never functions, so you could never directly check the function the symbol maps to.
(call-special #(println % " World") "Hello") contains reader macro code. Since reader macros are executed before regular macros, you should expand this before doing any more analysis. Do this by applying (read-string "(call-special #(println % \" World\") \"Hello\")") which becomes (call-special (fn* [p1__417#] (println p1__417# "world")) "Hello").
While generally speaking, it's not obvious when you would want to use something when you should probably use alternative methods, here's how I would approach it.
You'll need to call macroexpand-all on a. If the code eventually becomes a (fn*) form, then it is guaranteed to be a function. Then you can safely emit (~a ~b). If it macroexpands to eventually be a symbol, you can also emit (~a ~b). If the symbol wasn't a function, then an error would throw at runtime. Lastly, if it macroexpands into a list (a function call or special form call), like (println ...), then you can emit code that uses the thread macro ->.
You can also cover the cases such as when the form macroexpands into a data structure, but you haven't specified the desired behavior.
a in your macro is just a clojure list data structure (it is not a function yet). So basically you need to check whether the data structure a will result is a function or not when it is evaluated, which can be done like show below:
(defmacro call-special? [a b]
(if (or (= (first a) 'fn) (= (first a) 'fn*))
`(~a ~b)
`(-> ~b ~a)))
By checking whether the first element of the a is symbol fn* or fn
which is used to create functions.
This macro will only work for 2 cases: either you pass it a anonymous function or an expression.