I want to add the values from a map on clojure with the next code:
(letfn [(r [l a]
(if (empty? l)
a
(if (map? l)
(r (first(vals l)) (+ a (first (vals l))))
(r (rest l) (+ a (first l))))))]
(r {:a 1 :b 2 :c 3} 0)
but I get the following error:
IllegalArgumentException Don't know how to create ISeq from: java.lang.Long clojure.lang.RT.seqFrom (RT.java:542)
The problem is that in your code you are testing for empty on l, without being sure that l is a seq. You should look further in the stacktrace for that:
Don't know how to create ISeq from: java.lang.Long
RT.java: 528 clojure.lang.RT/seqFrom
RT.java: 509 clojure.lang.RT/seq
core.clj: 137 clojure.core/seq
core.clj: 5948 clojure.core/empty? <------
REPL: 13 user/eval19330/r
REPL: 16 user/eval19330/r
REPL: 21 user/eval19330
This happens because (first (vals l)) that is passed as the l parameter to the next iteration is a number and not a seq, in your case it is simply the value 1.
Your function r can only handle collections (as you call empty? and then test on map? and otherwise call rest). You probably want to recurse like this:
(letfn [(r [l a]
(if (empty? l)
a
(if (map? l)
(let [[key val] (first l)]
(r (dissoc l key) (+ a val)))
(r (rest l) (+ a (first l))))))]
(list (r {:a 1 :b 2 :c 3} 0)
(r [1 2 3] 0)))
This code will give the same error:
(empty? (first (vals {:a 1 :b 2 :c 3})))
Also
(empty? 2)
Also
(concat [3] 2 [4])
Related
Consider this simple-minded recursive implementation of comp in Clojure:
(defn my-comp
([f]
(fn [& args]
(apply f args)))
([f & funcs]
(fn [& args]
(f (apply (apply my-comp funcs) args)))))
The right way to do this, I am told, is using recur, but I am unsure how recur works. In particular: is there a way to coax the code above into being recurable?
evaluation 1
First let's visualize the problem. my-comp as it is written in the question will create a deep stack of function calls, each waiting on the stack to resolve, blocked until the the deepest call returns -
((my-comp inc inc inc) 1)
((fn [& args]
(inc (apply (apply my-comp '(inc inc)) args))) 1)
(inc (apply (fn [& args]
(inc (apply (apply my-comp '(inc)) args))) '(1)))
(inc (inc (apply (apply my-comp '(inc)) '(1))))
(inc (inc (apply (fn [& args]
(apply inc args)) '(1))))
(inc (inc (apply inc '(1)))) ; ⚠️ deep in the hole we go...
(inc (inc 2))
(inc 3)
4
tail-recursive my-comp
Rather than creating a long sequence of functions, this my-comp is refactored to return a single function, which when called, runs a loop over the supplied input functions -
(defn my-comp [& fs]
(fn [init]
(loop [acc init [f & more] fs]
(if (nil? f)
acc
(recur (f acc) more))))) ; 🐍 tail recursion
((my-comp inc inc inc) 1)
;; 4
((apply my-comp (repeat 1000000 inc)) 1)
;; 1000001
evaluation 2
With my-comp rewritten to use loop and recur, we can see linear iterative evaluation of the composition -
((my-comp inc inc inc) 1)
(loop 1 (list inc inc inc))
(loop 2 (list inc inc))
(loop 3 (list inc))
(loop 4 nil)
4
multiple input args
Did you notice ten (10) apply calls at the beginning of this post? This is all in service to support multiple arguments for the first function in the my-comp sequence. It is a mistake to tangle this complexity with my-comp itself. The caller has control to do this if it is the desired behavior.
Without any additional changes to the refactored my-comp -
((my-comp #(apply * %) inc inc inc) '(3 4)) ; ✅ multiple input args
Which evaluates as -
(loop '(3 4) (list #(apply * %) inc inc inc))
(loop 12 (list inc inc inc))
(loop 13 (list inc inc))
(loop 14 (list inc))
(loop 15 nil)
15
right-to-left order
Above (my-comp a b c) will apply a first, then b, and finally c. If you want to reverse that order, a naive solution would be to call reverse at the loop call site -
(defn my-comp [& fs]
(fn [init]
(loop [acc init [f & more] (reverse fs)] ; ⚠️ naive
(if (nil? f)
acc
(recur (f acc) more)))))
Each time the returned function is called, (reverse fs) will be recomputed. To avoid this, use a let binding to compute the reversal just once -
(defn my-comp [& fs]
(let [fs (reverse fs)] ; ✅ reverse once
(fn [init]
(loop [acc init [f & more] fs]
(if (nil? f)
acc
(recur (f acc) more))))))
a way to do this, is to rearrange this code to pass some intermediate function back up to the definition with recur.
the model would be something like this:
(my-comp #(* 10 %) - +)
(my-comp (fn [& args] (#(* 10 %) (apply - args)))
+)
(my-comp (fn [& args]
((fn [& args] (#(* 10 %) (apply - args)))
(apply + args))))
the last my-comp would use the first my-comp overload (which is (my-comp [f])
here's how it could look like:
(defn my-comp
([f] f)
([f & funcs]
(if (seq funcs)
(recur (fn [& args]
(f (apply (first funcs) args)))
(rest funcs))
(my-comp f))))
notice that despite of not being the possible apply target, the recur form can still accept variadic params being passed as a sequence.
user> ((my-comp (partial repeat 3) #(* 10 %) - +) 1 2 3)
;;=> (-60 -60 -60)
notice, though, that in practice this implementation isn't really better than yours: while recur saves you from stack overflow on function creation, it would still overflow on application (somebody, correct me if i'm wrong):
(apply my-comp (repeat 1000000 inc)) ;; ok
((apply my-comp (repeat 1000000 inc)) 1) ;; stack overflow
so it would probably be better to use reduce or something else:
(defn my-comp-reduce [f & fs]
(let [[f & fs] (reverse (cons f fs))]
(fn [& args]
(reduce (fn [acc curr-f] (curr-f acc))
(apply f args)
fs))))
user> ((my-comp-reduce (partial repeat 3) #(* 10 %) - +) 1 2 3)
;;=> (-60 -60 -60)
user> ((apply my-comp-reduce (repeat 1000000 inc)) 1)
;;=> 1000001
There is already a good answer above, but I think the original suggestion to use recur may have been thinking of a more manual accumulation of the result. In case you haven't seen it, reduce is just a very specific usage of loop/recur:
(ns tst.demo.core
(:use demo.core tupelo.core tupelo.test))
(defn my-reduce
[step-fn init-val data-vec]
(loop [accum init-val
data data-vec]
(if (empty? data)
accum
(let [accum-next (step-fn accum (first data))
data-next (rest data)]
(recur accum-next data-next)))))
(dotest
(is= 10 (my-reduce + 0 (range 5))) ; 0..4
(is= 120 (my-reduce * 1 (range 1 6))) ; 1..5 )
In general, there can be any number of loop variables (not just 2 like for reduce). Using loop/recur gives you a more "functional" way of looping with accumulated state instead of using and atom and a doseq or something. As the name suggests, from the outside the effect is quite similar to a normal recursion w/o any stack size limits (i.e. tail-call optimization).
P.S. As this example shows, I like to use a let form to very explicitly name the values being generated for the next iteration.
P.P.S. While the compiler will allow you to type the following w/o confusion:
(ns tst.demo.core
(:use demo.core tupelo.core tupelo.test))
(defn my-reduce
[step-fn accum data]
(loop [accum accum
data data]
...))
it can be a bit confusing and/or sloppy to re-use variable names (esp. for people new to Clojure or your particular program).
Also
I would be remiss if I didn't point out that the function definition itself can be a recur target (i.e. you don't need to use loop). Consider this version of the factorial:
(ns tst.demo.core
(:use demo.core tupelo.core tupelo.test))
(defn fact-impl
[cum x]
(if (= x 1)
cum
(let [cum-next (* cum x)
x-next (dec x)]
(recur cum-next x-next))))
(defn fact [x] (fact-impl 1 x))
(dotest
(is= 6 (fact 3))
(is= 120 (fact 5)))
I do the following code to retrieve only the keys of a plist:
(loop :for (key nil) :on config :by #'cddr
:collect key))
Running this produces:
CONFIG-TEST> (loop :for (key nil) :on '(:foo 1 :bar 2) :by #'cddr
:collect key)
(:FOO :BAR)
Is there a more 'functional' way to do this than using LOOP?
Not really...
CL-USER 35 > (let ((? nil))
(mapcon (lambda (l)
(when (setf ? (not ?))
(list (first l))))
'(:foo 1 :bar 2)))
(:FOO :BAR)
or maybe:
(defun mapncar (fn list &key (start 0) (n 1))
(loop for l = (nthcdr start list) then (nthcdr n l)
while l
collect (funcall fn (first l))))
CL-USER 61 > (mapncar #'identity '(a 1 b 2 c 3) :n 2)
(A B C)
CL-USER 62 > (mapncar #'identity '(a 1 b 2 c 3) :start 1 :n 2)
(1 2 3)
Using the SERIES package, scan-plist returns two series, one for the keys, the other for values:
(scan-plist '(:a 3 :b 2))
=> #Z(:A :B)
#Z(3 2)
You can rely on this to collect the first series as a list:
(collect 'list (scan-plist '(:a 3 :b 2)))
More generally, you may want to process the values in some way, so you would use mapping. For example, here is a plist-alist made with SERIES:
(defun plist-alist (plist)
(collect 'list
(mapping (((k v) (scan-plist plist))) (cons k v))))
What stylistic direction would do take us?
CL-USER> (do ((result (list) (cons (car plist) result))
(plist '(:foo 1 :bar 2) (cddr plist)))
((null plist) (reverse result)))
(:FOO :BAR)
By the way, I'd write the loop with less syntax, will this bite me?
CL-USER> (loop for key in '(:foo 1 :bar 2) by 'cddr
collecting key)
(:FOO :BAR)
If you are sure that none of the values are of type symbol, you could filter for symbols:
(remove-if-not #'symbolp '(:a 1 :b 2)) ;;=> (:A :B)
Much less efficient, but universersal:
filter for symbolp and getf-ability
(Only keys of a plist are getf-able from the plist, thus this is the check whether it is a key or not. However, a check, whether an element in a plist is symbolp is cheaper and removes most of the non-key values,
thus saving time and cost).
(defun get-plist-keys (plist)
(remove-if-not #'(lambda (x) (and (symbolp x) (getf plist x))) plist))
(get-plist-keys '(:a 1 :b 2 :c :d))
;; => (:A :B :C)
(ql:quickload :alexandria)
(mapcar #'car (alexandria:plist-alist '(:a 1 :b 2)))
;; => (:A :B)
To remove dependency of alexandria, define yourself plist-alist:
(defun plist-alist (l &optional (acc '()))
(cond ((null l) (nreverse acc))
(t (plist-alist (cddr l) (cons (cons (car l) (cadr l)) acc)))))
However, dependency on :alexandria should not be counted as dependency.
directly
Actyally, one could change plist-alist definition to obtain only the keys:
(defun plist-keys (l &optional (acc '()))
(cond ((null l) (nreverse acc))
(t (plist-keys (cddr l) (cons (car l) acc)))))
And likewise the values:
(defun plist-vals (l &optional (acc '()))
(cond ((null l) (nreverse acc))
(t (plist-vals (cddr l) (cons (cadr l) acc)))))
With the Serapeum library, which I consider as a second must-have just after Alexandria: use plist-keys :)
(serapeum:plist-keys '(:a 1 :b 2))
;; (:A :B)
https://github.com/ruricolist/serapeum/blob/master/REFERENCE.md#plist-keys-plist
Here's its implementation:
(defun plist-keys (plist)
"Return the keys of a plist."
(collecting*
(doplist (k v plist)
(collect k))))
It also has plist-values.
I'm trying some lazy streams in Clojure.
If I do:
(defn ints-from [n]
(cons n (lazy-seq (ints-from (inc n)))))
and
(def nats (ints-from 0))
it's fine, I can do something like:
(take 5 nats)
Now I'm trying to encapsulate the 2 functions in 1:
(defn natz[]
( letfn [(aux [n]((cons n (lazy-seq (aux (inc n)))))) ] (aux 0) ))
This seems to compile, but does not do what I expect.
(take 4 natz)
gives:
(user=> IllegalArgumentException Don't know how to create ISeq from: user$natz
clojure.lang.RT.seqFrom (RT.java:494)
What am I missing?
One parenthesis less inside letfn definition and one parenthesis more to invoke natz function
(defn natz[]
(letfn [(aux [n] (cons n (lazy-seq (aux (inc n)))))]
(aux 0)))
Example usage:
(take 4 (natz))
=> (0 1 2 3)
I'm currently going through the 4clojure Problem 23
My current solution uses recursion to go through the list and append each element to the end of the result of the same function:
(fn self [x] (if (= x [])
x
(conj (self (rest x)) (first x))
))
But when I run it against [1 2 3] it gives me (1 2 3)
What I think it should be doing through recursion is:
(conj (conj (conj (conj (conj [] 5) 4) 3) 2) 1)
which does return
[5 4 3 2 1]
But it is exactly the opposite, so I must be missing something. Also, I don't understand why ones return a vector and the other one returns a list.
When you do (rest v) you're getting a list (not a vector), and then conj is appending to the front each time (not the back):
user=> (defn self [v] (if (empty? v) v (conj (self (rest v)) (first v))))
#'user/self
user=> (self [1 2 3])
(1 2 3)
user=> (defn self [v] (if (empty? v) [] (conj (self (rest v)) (first v))))
#'user/self
user=> (self [1 2 3])
[3 2 1]
user=>
user=> (rest [1])
()
user=> (conj '() 2)
(2)
user=> (conj '(2) 1)
(1 2)
user=>
Given a function object or name, how can I determine its arity? Something like (arity func-name) .
I hope there is a way, since arity is pretty central in Clojure
The arity of a function is stored in the metadata of the var.
(:arglists (meta #'str))
;([] [x] [x & ys])
This requires that the function was either defined using defn, or the :arglists metadata supplied explicitly.
Sneaky reflection:
(defn arg-count [f]
(let [m (first (.getDeclaredMethods (class f)))
p (.getParameterTypes m)]
(alength p)))
Or :
(defn arg-count [f]
{:pre [(instance? clojure.lang.AFunction f)]}
(-> f class .getDeclaredMethods first .getParameterTypes alength))
Building on #whocaresanyway's solution:
(defn provided
[cond fun x]
(if cond
(fun x)
x))
(defn append
[xs x]
(conj (vec xs) x))
(defn arity-of-method
[method]
(->> method .getParameterTypes alength))
(defn arities
[fun]
(let [all-declared-methods (.getDeclaredMethods (class fun))
methods-named (fn [name]
(filter #(= (.getName %) name) all-declared-methods))
methods-named-invoke (methods-named "invoke")
methods-named-do-invoke (methods-named "doInvoke")
is-rest-fn (seq methods-named-do-invoke)]
(->> methods-named-invoke
(map arity-of-method)
sort
(provided is-rest-fn
(fn [v] (append v :rest))))))
My heart bled (covered all the cases).
(defn arity
"Returns the maximum arity of:
- anonymous functions like `#()` and `(fn [])`.
- defined functions like `map` or `+`.
- macros, by passing a var like `#'->`.
Returns `:variadic` if the function/macro is variadic."
[f]
(let [func (if (var? f) #f f)
methods (->> func class .getDeclaredMethods
(map #(vector (.getName %)
(count (.getParameterTypes %)))))
var-args? (some #(-> % first #{"getRequiredArity"})
methods)]
(if var-args?
:variadic
(let [max-arity (->> methods
(filter (comp #{"invoke"} first))
(sort-by second)
last
second)]
(if (and (var? f) (-> f meta :macro))
(- max-arity 2) ;; substract implicit &form and &env arguments
max-arity)))))
(use 'clojure.test)
(defmacro m ([a]) ([a b]))
(defmacro mx [])
(deftest test-arity
(testing "with an anonymous #(… %1) function"
(is (= 1 (arity #(+ % 32))))
(is (= 1 (arity #(+ %1 32))))
(is (= 2 (arity #(+ %1 %2))))
(is (= 13 (arity #(+ %1 %2 %3 %4 %5 %6 %7 %8 %9 %10 %11 %12 %13))))
(is (= :variadic (arity #(apply + %&))))
(is (= :variadic (arity #(apply + % %&)))))
(testing "with an anonymous (fn [] …) function"
(testing "single body"
(is (= 0 (arity (fn []))))
(is (= 1 (arity (fn [a]))))
(is (= 2 (arity (fn [a b]))))
(is (= 20 (arity (fn [a b c d e f g h i j k l m n o p q r s t]))))
(is (= :variadic (arity (fn [a b & more])))))
(testing "multiple bodies"
(is (= 0 (arity (fn ([])))))
(is (= 1 (arity (fn ([a])))))
(is (= 2 (arity (fn ([a]) ([a b])))))
(is (= :variadic (arity (fn ([a]) ([a b & c])))))))
(testing "with a defined function"
(is (= :variadic (arity map)))
(is (= :variadic (arity +)))
(is (= 1 (arity inc))))
(testing "with a var to a macro"
(is (= :variadic (arity #'->)))
(is (= 2 (arity #'m)))
(is (= 0 (arity #'mx)))))
(run-tests)
Actually it also works on macros:
(defn arg-count [f]
(let [m (first (.getDeclaredMethods (class f)))
p (.getParameterTypes m)]
(alength p)))
(defmacro my-macro [])
(arg-count ##'my-macro)
; 2
Why 2? Because every macro has two implicit arguments &form and &env respectively.
My take at the arity problem, building on the other solutions:
(defn arity
"Returns the maximum parameter count of each invoke method found by refletion
on the input instance. The returned value can be then interpreted as the arity
of the input function. The count does NOT detect variadic functions."
[f]
(let [invokes (filter #(= "invoke" (.getName %1)) (.getDeclaredMethods (class f)))]
(apply max (map #(alength (.getParameterTypes %1)) invokes))))
user=> (defn test-func
([p1] "Arity was 1.")
([p1 p2] "Arity was 2.")
([p1 p2 & more-args] (str "Arity was " (+ 2 (count more-args)))))
#'user/test-func
user=> (test-func 1)
"Arity was 1."
user=> (test-func 1 2)
"Arity was 2."
user=> (test-func 1 2 3)
"Arity was 3"
user=> (test-func 1 2 3 4)
"Arity was 4"
user=> (test-func 1 2 3 4 5) ;...
"Arity was 5"