I'm trying to figure why this particular function isn't working as expected. I suspect from the error message that it has something to do with the way I'm creating the empty vector for the accumulator.
I have a simple function that returns a sequence of 2-element vectors:
(defn zip-with-index
"Returns a sequence in which each element is of the
form [i c] where i is the index of the element and c
is the element at that index."
[coll]
(map-indexed (fn [i c] [i c]) coll))
That works fine. The problem comes when I try to use it in another function
(defn indexes-satisfying
"Returns a vector containing all indexes of coll that satisfy
the predicate p."
[p coll]
(defn accum-if-satisfies [acc zipped]
(let [idx (first zipped)
elem (second zipped)]
(if (p elem)
(conj acc idx)
(acc))))
(reduce accum-if-satisfies (vector) (zip-with-index coll)))
It compiles, but when I attempt to use it I get an error:
user=> (indexes-satisfying (partial > 3) [1 3 5 7])
ArityException Wrong number of args (0) passed to: PersistentVector
clojure.lang.AFn.throwArity (AFn.java:437)
I can't figure out what's going wrong here. Also if there is a more 'Clojure-like' way of doing what I'm trying to do, I'm interested in hearing about that also.
The problem is probably on the else clause of accum-if-satisfies, should be just acc not (acc).
You could use filter and then map instead of reduce. Like that:
(map #(first %)
(filter #(p (second %))
(zip-with-index coll)))
You could also call map-indexed with vector instead of (fn [i c] [i c]).
The whole code would look like that:
(defn indexes-satisfying
[p coll]
(map #(first %)
(filter #(p (second %))
(map-indexed vector coll))))
As for a more Clojure-like way, you could use
(defn indexes-satisfying [pred coll]
(filterv #(pred (nth coll %))
(range (count coll))))
Use filter instead of filterv to return a lazy seq rather than a vector.
Also, you should not use defn to define inner functions; it will instead define a global function in the namespace where the inner function is defined and have subtle side effects besides that. Use letfn instead:
(defn outer [& args]
(letfn [(inner [& inner-args] ...)]
(inner ...)))
One more way to do it would be:
(defn indexes-satisfying [p coll]
(keep-indexed #(if (p %2) % nil) coll))
Related
Which form is better?
(defn my-func [arg arg2]
(fn [] [:div (str arg arg2)]))
Or this one?
(defn my-func []
(fn [arg arg2] [:div (str arg arg2)]))
I'm writting from my phone so forgive me indentation...
There's other difference between these functions aside from arity.
The first function will close over arg, and arg2 on first render, and use these arguments for each subsequent rerender. E.g.
(def a 1)
(def b 2)
[my-func a b]
will always result in [:div '12'] whether or not a or b were changed
The second function will take arg, and arg2 on each render and will update the result when arguments change.
Look for Rookie mistake in reagent docs
I believe your question should be which one is correct(The first one is correct). The second one has got an arity exception. Based on your use case, I would prefer to define and call the anonymous function so as to get the results. Consider this number one edit:
(defn my-func [arg arg2]
((fn [] [:div (str arg arg2)])))
Consider the following hypothetical nonsensical ClojureScript function:
(defn tmp []
(def p 0)
(set! p (inc p))
(set! p (inc p))
(set! p (inc p)))
Repeatedly executing this function in a REPL results in
3
6
9
etc.
Is it possible to create a mutable variable which is local to the function, such that the output would have been
3
3
3
etc.
in the case of repeated exection of (tmp)?
let lets you assign variables limited to it's scope:
(defn tmp[]
(let [p 0]
...))
Now, clojurescript makes use of immutable data. That means everything is basically a constant, and once you set a value of p, there is no changing it. There are two ways you can get around this:
Use more local variables
(defn tmp[]
(let [a 0
b (inc a)
c (inc b)
d (inc c)]
...))
Use an atom
Atoms are somewhat different from other data structures in clojurescript and allow control of their state. Basically, you can see them as a reference to your value.
When creating an atom, you pass the initial value as its argument. You can access an atoms value by adding # in front of the variable, which is actually a macro for (deref my-var).
You can change the value of an atom using swap! and reset! functions. Find out more about them in the cljs cheatsheet.
(defn tmp[]
(let [p (atom 0)]
(reset! p (inc #p))
(reset! p (inc #p))
(reset! p (inc #p))))
Hope this helps.
Suppose I have the following clojure function call:
(def mymap {:a1 1 :a2 2})
(defn my-adder [input-map]
(let [a1 (:a1 input-map)
a2 (:a2 input-map)]
(+ a1 a2)))
(my-adder mymap)
What I'm looking for is for some way to make the my-adder function simpler by converting the map to params automatically - something like:
(defn my-adder [(magic-function input-map)]
(+ a1 a2))
Can someone point me to what I'm missing?
What I think you're looking for is destructuring. Here's what you can do:
(def mymap {:a1 1 :a2 2})
(defn my-adder [{:keys [a1 a2]}]
(+ a1 a2))
(my-adder mymap)
You can learn more about it here.
Use can use like bellow. It's called as Clojure: Destructuring. You can find more here
(defn my-adder [{a1 :a1 a2 :a2}]
(+ a1 a2))
In addition to the answers showing destructuring, you could also use apply and vals if simply adding all values from your map together is fine for you:
(defn my-adder [m]
(apply + (vals m)))
Or you can use the fnk function in the plumbing libary
(use 'plumbing.core)
(defnk my-adder [a b]
(+ a b))
I have the following problem. I'm doing WebCrawler for a school assignment, and I'm doing it in Clojure. Here is the code.
(defn crawl [url current-depth max-depth]
(def hrefs (get-links url))
(if (< current-depth max-depth)
(map crawl hrefs (iterate eval (inc current-depth)) (iterate eval max-depth))
hrefs))
(defn get-links [page]
($ (get! page) td "a[href]" (attr "abs:href")))
The get! and $ functions is not written by me, I've taken them from here: https://github.com/mfornos/clojure-soup/blob/master/src/jsoup/soup.clj
My problem is that when I call (crawl "http://bard.bg" 0 0) from repl I get the following output:
("http://www.bard.bg/genres/?id=1" "http://www.bard.bg/genres/?id=2" "http://www.bard.bg/genres/?id=4" "http://www.bard.bg/genres/?id=5" "http:/
("http://www.bard.bg/genres/?id=1" "http://www.bard.bg/genres/?id=2" "http://www.bard.bg/genres/?id=4" "http://www.bard.bg/genres/?id=5" "http:/
("http://www.bard.bg/genres/?id=1" "http://www.bard.bg/genres/?id=2" "http://www.bard.bg/genres/?id=4" "http://www.bard.bg/genres/?id=5" "http://www.bard.bg/genres/?id=6" "http://www.bard.bg/genres/?id=10" "http://www.bard.bg/genres/?id=17" "http://www.bard.bg/genres/?id=24"
...
So where do the first 2 lazyseqs are coming from? Why are they unfinished?
Seems like the problem is in the Clojure-Soup and more specifically here:
(defmacro $ [doc & forms]
(let [exprs# (map #(if (string? %) `(select ~%)
(if (symbol? %) `(select ~(str %))
(if (keyword? %) `(select ~(str "#"(name %)))
%))) forms)]
`(->> ~doc ~#exprs#)))`
I cannot reproduce the problem you described. In my case (crawl "http://bard.bg" 0 0) returns a list of 174 strings.
However, I'd like to take this opportunity to point you to an incorrect usage of def in the crawl function. Instead of def you should use let. Additionally, instead of (iterate eval ...) use repeat.
(defn crawl [url current-depth max-depth]
(let [hrefs (get-links url)]
(if (< current-depth max-depth)
(map crawl hrefs (repeat (inc current-depth)) (repeat max-depth))
hrefs)))
For discussion see let vs def in clojure.
I'm learning Clojure and I'm trying to define a function that take a variable number of parameters (a variadic function) and sum them up (yep, just like the + procedure). However, I donĀ“t know how to implement such function
Everything I can do is:
(defn sum [n1, n2] (+ n1 n2))
Of course this function takes two parameteres and two parameters only. Please teach me how to make it accept (and process) an undefined number of parameters.
In general, non-commutative case you can use apply:
(defn sum [& args] (apply + args))
Since addition is commutative, something like this should work too:
(defn sum [& args] (reduce + args))
& causes args to be bound to the remainder of the argument list (in this case the whole list, as there's nothing to the left of &).
Obviously defining sum like that doesn't make sense, since instead of:
(sum a b c d e ...)
you can just write:
(+ a b c d e ....)
Yehoanathan mentions arity overloading but does not provide a direct example. Here's what he's talking about:
(defn special-sum
([] (+ 10 10))
([x] (+ 10 x))
([x y] (+ x y)))
(special-sum) => 20
(special-sum 50) => 60
(special-sum 50 25) => 75
(defn my-sum
([] 0) ; no parameter
([x] x) ; one parameter
([x y] (+ x y)) ; two parameters
([x y & more] ; more than two parameters
(reduce + (my-sum x y) more))
)
defn is a macro that makes defining functions a little simpler.
Clojure supports arity overloading in a single function object,
self-reference, and variable-arity functions using &
From http://clojure.org/functional_programming
(defn sum [& args]
(print "sum of" args ":" (apply + args)))
This takes any number of arguments and add them up.