In my program I am trying to test my program by writing tests that verify the functionality of my defined functions. I am testing the equality of sequences after they have passed through my function.
Definition of my-reverse:
(defn my-reverse [coll]
(if (empty? coll)
[]
(conj
(my-reverse (rest coll))
(first coll)
)
)
)
I do not know why I am failing the assertion, as (my-reverse [1]) returns [1].
Here is the assertion:
(assert (identical? (my-reverse [1]) [1]))
Thank you all in advance!
identical? only returns true if the arguments refer to the same object, which will not be the case if your my-reverse function constructs a new list. You can just use =:
(assert (= (my-reverse [1]) [1]))
Related
I'm going over SICP translating problems into Clojure to learn both Clojure and read SICP. Currently, I am stuck with the Count Leaves procedure from Section 2.2.2.
The goal is to write a function that takes a list representation of a tree, e.g. '(1 2 '(3 4)) and counts the number of leaves, in this case 4.
So far, the closest I have come up with is
(defn count-leaves
[coll]
(cond
(nil? coll) 0
(not (seq? coll)) 1
:else (let [[left & right] coll] (+ (count-leaves left) (count-leaves right)))
))
However, this does not handle subtrees correctly. In particular, it evaluates
(count-leaves '('(1)))
to 2 instead of 1.
Note the Scheme implementation from the book is:
(define (count-leaves x)
(cond ((null? x) 0)
((not (pair? x)) 1)
(else (+ (count-leaves (car x))
(count-leaves (cdr x))))))
Comment
As #jkiski's comment suggests, your code works. So there is no problem.
But I'd prefer to test whether the argument is a sequence first. Try working out how (count-leaves '()) evaluates to 0!
Switch the first two clauses of the cond and we get ...
(defn count-leaves [coll]
(cond
(not (seq? coll)) 1
(empty? coll) 0
:else (+ (count-leaves (first coll)) (count-leaves (rest coll)))))
... where I've used rest instead of the next implicit in the destructuring, so empty? instead of nil? to test it. This deals properly with nil values, which your code doesn't. But it is still properly recursive, so remains subject to stack overflow.
I prefer ...
(defn count-leaves [coll]
(if (seq? coll)
(apply + (map count-leaves coll))
1))
... which is still recursive, but cleaner.
Edit
I've had to retract my good opinion of #glts's solution: postwalk is recursive, so offers no real advantage.
Translating examples from one language into another is a good exercise, but do keep in mind that a language also comes with its own idiom, and its own core library.
In Clojure, walking data structures is especially easy with clojure.walk.
After requiring clojure.walk you can run postwalk-demo to see how your data structure is traversed:
(require '[clojure.walk :refer [postwalk postwalk-demo]])
(postwalk-demo '(1 2 (3 4)))
Walked: 1
Walked: 2
Walked: 3
Walked: 4
Walked: (3 4)
Walked: (1 2 (3 4))
Then you can devise a function to count the leaf nodes and pass it to postwalk.
(postwalk (fn [e]
(if (seq? e) (apply + e) 1))
'(1 2 (3 4)))
During the postwalk traversal leaf nodes get replaced with 1, and seqs get replaced with the sum of their constituent leaf counts.
I realise that this is a tangential answer but perhaps you still find it useful!
I have this Lisp code, and I'm trying to convert it into Clojure code.
(defun copy-tree (tr)
(if (atom tr)
tr
(cons (copy-tree (car tr))
(copy-tree (crd tr)))))
It seems like that Clojure doesn't have Lisp's atom (or atom in Clojure has very different meaning), I had to modify the code as follows. (Am I using atom? wrong or there is something else....?)
(defn single-valued?
[x]
(not (or (nil? x)
(.. x getClass isArray)
(some #(instance? % x) [clojure.lang.Counted
clojure.lang.IPersistentCollection
java.util.Collection
java.util.Map]))))
(defn copy-tree [tr]
(if (or (= tr ()) (single-valued? tr))
tr
(cons (copy-tree (first tr))
(copy-tree (rest tr)))))
The code works fine, but is there better way to replace Lisp's atom function?
I think you'll find this behaves apropriately:
(def single-valued? (complement coll?))
the difference is that it will bottom out sooner for nil -- (rest nil) is () which finally does not recur, but ((complement coll?) nil) returns true, so stops the recursion one step sooner.
I am very surprised by the behaviour of identical? in clojure.
(def a (map identity [:a :b]))
(identical? (rest a) (rest a)); false
Any idea why identical? returns false?
identical?:
Tests if 2 arguments are the same object
Since rest creates a new seq object on each invocation, its results are not identical?. The following, however, is:
(def r (rest (map identity [:a :b])))
(identical? r r) ;; => true
Update: As #mfikes pointed out, rest does not always create a new seq. It calls ISeq.more() internally which is implemented per seq type and might yield different results for lists, vectors, lazy seqs, etc.:
(->> [(map identity [:a :b])
(vector :a :b)
(list :a :b)]
(map #(identical? (rest %) (rest %))))
;; => [false false true]
identical? is the object equality predicate. It returns true if its arguments are the same object/primitive.
Use = over identical?.
identical? is the correct tool when semantics depend on pointer equality, such as testing for an end-of-file sentinel value.
Never use identical? to compare Clojure data structures. Even keywords don't guarantee identical? behaves correctly.
Are there non-macro versions of and and or in Clojure?
Update: In this case I don't care about the short circuiting.
or
The function some "Returns the first logical true value of (pred x) for any x in coll, else nil."
So you could use (some identity coll) for or. Note that its behaviour will differ from or when the last value is false: it will return nil where or would return false.
and
If you don't need to know the value of the last form in the coll vector, you can use (every? identity coll) for and. This will differ from the behaviour of the and macro in that it returns true if all of its arguments are truthy. See larsmans' answer if you need the result of the last form.
Let land stand for "logical and", then they're trivial to define:
(defn land
([] true)
([x & xs] (and x (apply land xs))))
Or, slightly closer to the standard and behavior:
(defn land
([] true)
([x] x)
([x & xs] (and x (apply land xs))))
And similarly for or.
This actually came up as a topic on clojure-dev recently. Rich Hickey ultimately concluded they should be added to core for 1.3 as every-pred and any-pred (logged as CLJ-729). I think further discussions there have led them to now be called every-pred (the and variant) and some-fn (the or variant). The final version was just recently committed to master.
If you mean functions: no, and they cannot be. The reason is that function forms always evaluate all their arguments before applying the function to their value. You do not want that here.
Most cases where you want this there is a more idiomatic way to do it, but just an exercise, it is possible to defer evaluation by thunking. Thunk your expressions and give them to logical operators that evaluate the the thunk when needed, using the standard and/or:
(defn &&* [& fns]
(cond (= 1 (count fns)) ((first fns))
:otherwise
(and ((first fns)) (apply &&* (next fns)))))
(defn ||* [& fns]
(cond (= 1 (count fns)) ((first fns))
:otherwise
(or ((first fns)) (apply ||* (next fns)))))
Example use:
(map
(partial apply &&*)
(map (partial map constantly) ;; thunk all of these values
[["yes" "no"]
[false true]
[true "something"]
[true "something" "false"]]))
("no" false "something" "false")
Another Example:
(defmacro thunks
"convert expressions into thunks to prevent advance evaluation"
[& exprs]
(let [fns# (map (fn [e] `(fn [] ~e)) exprs)]
(cons 'vector fns#)))
(apply ||* (thunks (+ 1 2) false (* 1 5)))
3
(apply &&* (thunks (+ 1 2) false (* 1 5)))
false
(apply &&* (thunks (+ 1 2) (* 1 5)))
5
In Common Lisp you use the (null x) function to check for empty lists and nil values.
Most logically this maps to
(or (nil? x) (= '() x))
In clojure. Can someone suggest a more idiomatic way to do it in Clojure?
To get the same result for an empty list in Clojure as you do in Common Lisp, use the empty? function. This function is in the core library: no imports are necessary.
It is also a predicate, and suffixed with a ?, making it a little clearer what exactly you're doing in the code.
=> (empty? '())
true
=> (empty? '(1 2))
false
=> (empty? nil)
true
As j-g faustus already noted, seq can be used for a similar effect.
seq also serves as test for end,
already idiomatic
(when (seq coll)
...)
From clojure.org lazy
It works because (seq nil) and (seq ()) both return nil.
And since nil means false, you don't need an explicit nil test.