What is the difference between seq and seq? - clojure

-------------------------
clojure.core/seq
([coll])
Returns a seq on the collection. If the collection is
empty, returns nil. (seq nil) returns nil. seq also works on
Strings, native Java arrays (of reference types) and any objects
that implement Iterable.
-------------------------
clojure.core/seq?
([x])
Return true if x implements ISeq
-----
Obviously empty? is based on seq. what is the difference between empty? and nil? I'm soooo confused.
clojure.core/empty?
([coll])
Returns true if coll has no items - same as (not (seq coll)).
Please use the idiom (seq x) rather than (not (empty? x))
And more:
(not (seq? ())) ;;false
(not (seq ())) ;;true
(not nil) ;;true

seq converts collection to sequence and returns nil if the collection is empty; also returns nil if the argument is nil.
seq? returns true if the argument is a sequence (implements the ISeq interface).
empty? will return true if the argument is either nil or an empty collection.
nil? will return true if the argument is nil.
I guess the bit about the (seq x) idiom in the docstring for empty? applies to common practice of using if-let like so:
(defn print-odd-numbers [coll]
(if-let [x (seq (filter odd? coll))]
(println "Odd numbers:" x)
(println "No odd numbers found.")))

Related

Clojure function/macro to apply functions until one returns something other than nil

Currently I have some code like this:
(defn compute-issue [some args] (or (age-issue some args) (name-issue some args)))
More issue types are coming.
Is there something like this:
(defn compute-issue [some args] (first-not-nil [age-issue name-issue] some args))
; Where first-not-nil would be something like
(defn first-not-nil [fs & args]
(if (empty? fs)
nil
(let [result (apply (first fs) args)]
(if (nil? result)
(recur (rest fs) args)
result))))
I'm new to Clojure. Am I reinventing an existing function?
There is a similar function some-fn in clojure.core:
Takes a set of predicates and returns a function f that returns the first logical true value
returned by one of its composing predicates against any of its arguments, else it returns
logical false. Note that f is short-circuiting in that it will stop execution on the first
argument that triggers a logical true result against the original predicates.
The key differences are some-fn returns another function for the actual function application, and that function will also discard false results, which it sounds like you may not want. This is another simple way to phrase it:
(defn first-not-nil [fs & args]
(first
(for [f fs
:let [r (apply f args)]
:when (some? r)]
r)))

Unexpected behavior when using recur in a variadic function

I was writing an answer for this challenge, when I needed to give a recursive function an optional parameter. I ended up with something kind of equivalent to:
(defn func [a & [b?]]
(if b?
b?
(recur a a)))
My intent was for b? to act as an optional parameter. If it wasn't supplied, it would be defaulted to nil via destructuring.
Instead of running though, it gave me an error:
(func 1)
UnsupportedOperationException nth not supported on this type: Long clojure.lang.RT.nthFrom (RT.java:947)
After some debugging, I realized that for some reason the rest parameter wasn't a list as I'd expect, but just the passed number! The error was coming about because it tried to destructure the number.
I can fix it by getting rid of the wrapper list in the parameter list:
(defn func [a & b]
...
But this just looks wrong. I know the rest parameter should be a list, but b is actually just a number. If I use "unoptimized" recursion, it works as I'd expect:
(defn func2 [a & [b?]]
(if b?
b?
(func2 a a)))
(func2 1)
=> 1
Can anyone explain what's going on here?
This appears to be a known difference
; Note that recur can be surprising when using variadic functions.
(defn foo [& args]
(let [[x & more] args]
(prn x)
(if more (recur more) nil)))
(defn bar [& args]
(let [[x & more] args]
(prn x)
(if more (bar more) nil)))
; The key thing to note here is that foo and bar are identical, except
; that foo uses recur and bar uses "normal" recursion. And yet...
user=> (foo :a :b :c)
:a
:b
:c
nil
user=> (bar :a :b :c)
:a
(:b :c)
nil
; The difference arises because recur does not gather variadic/rest args
; into a seq.
It's the last comment that describes the difference.

Clojure flexible function design based on arguments?

I have functions that behave different depending on which keyword arguments have values supplied. For this question, I am wondering about functions that behave slightly differently depending on the type of argument supplied.
Example function, that increments each element of a list:
(defn inc-list [& {:keys [list-str list]}]
(let [prepared-list (if-not (nil? list) list (clojure.string/split list-str #","))]
(map inc prepared-list)))
Does it make sense to make a multimethod that instead tests for the type of argument? I have not used multimethods before, not sure about right time to use them. If it is a good idea, would the below example make sense?
Example:
(defn inc-coll [col] (map inc col))
(defmulti inc-list class)
(defmethod inc-list ::collection [col] (inc-col col))
(defmethod inc-list String [list-str]
(inc-col
(map #(Integer/parseInt %)
(clojure.string/split list-str #",")))
First things first: (map 'inc x) treats each item in x as an associative collection, and looks up the value indexed by the key 'inc.
user> (map 'inc '[{inc 0} {inc 1} {inc 2}])
(0 1 2)
you probably want inc instead
user> (map inc [0 1 2])
(1 2 3)
Next, we have an attempt to inc a string, the args to string/split out of order, and some spelling errors.
If you define your multi to dispatch on class, then the methods should be parameterized by the Class, not a keyword placeholder. I changed the multi so it would work on anything Clojure knows how to treat as a seq. Also, as a bit of bikeshedding, it is better to use type, which offers some distinctions for differentiating inputs in Clojure code that class does not offer:
user> (type (with-meta {:a 0 :b 1} {:type "foo"}))
"foo"
Putting it all together:
user> (defn inc-coll [col] (map inc col))
#'user/inc-coll
user> (defmulti inc-list type)
nil
user> (defmethod inc-list String [list-str]
(inc-coll (map #(Integer/parseInt %) (clojure.string/split list-str #","))))
#<MultiFn clojure.lang.MultiFn#6507d1de>
user> (inc-list "1,10,11")
(2 11 12)
user> (defmethod inc-list clojure.lang.Seqable [col] (inc-coll (seq col)))
#<MultiFn clojure.lang.MultiFn#6507d1de>
user> (inc-list [1 2 3])
(2 3 4)
Your first example is an obfuscated application of a technique called dispatching on type. It is obfuscated because in a message-passing style the caller must convey the type to your function.
Since in every case you only use one of the keyword args, you could as well define it as:
(defn inc-list
[m l]
(->> (case m ;; message dispatch
:list l
:list-str (map #(edn/read-string %) (str/split #",")) l)
(map inc)))
The caller could be relieved from having to pass m:
(defn inc-list
[l]
(->> (cond (string? l) (map ...)
:else l)
(map inc)))
This technique has the main disadvantage that the operation procedure code must be modified when a new type is introduced to the codebase.
In Clojure it is generally superseeded by the polymorphism construct protocols, e. g.:
(defprotocol IncableList
(inc-list [this]))
Can be implemented on any type, e. g.
(extend-type clojure.lang.Seqable
IncableList
(inc-list [this] (map inc this)))
(extend-type String
IncableList
(inc-list [this] (map #(inc ...) this)))
Multimethods allow the same and provide additional flexibility over message-passing and dispatching on type by decoupling the dispatch mechanism from the operation procedures and providing the additivity of data-directed programming. They perform slower than protocols, though.
In your example the intention is to dispatch based on type, so you don't need multimethods and protocols are the appropriate technique.

Why doesn't (into {} x) accept a sequence of sequences for x

=> (into {} (for [x [["1" "2"] ["3" "4"]]] (map #(Long/parseLong %) x)))
ClassCastException java.lang.Long cannot be cast to java.util.Map$Entry clojure.lang.ATransientMap.conj (ATransientMap.java:44)
=> (into {} (for [x [["1" "2"] ["3" "4"]]] (seq (map #(Long/parseLong %) x))))
ClassCastException java.lang.Long cannot be cast to java.util.Map$Entry clojure.lang.ATransientMap.conj (ATransientMap.java:44)
=> (into {} (for [x [["1" "2"] ["3" "4"]]] (vec (map #(Long/parseLong %) x))))
{1 2, 3 4}
I've got two related questions:
How come (into {}) insists on vector as the container of a (key,value) pair?
Why is it trying to use the Long, which is the constituent of the pair, as the pair itself? Shouldn't it at least complain about seeing a non-vector, regardless of what it contains?
BTW testing with Clojure 1.5.1.
To answer the second question: you're passing a sequence of sequences to into. into works by repeated conjing (or conj!ing, if possible; the result is equivalent). Here at each step you'll be taking one item from your sequence of sequences and conjing it on to the map. Each such item is a sequence of two Longs. When you conj a sequence on to a map, conj assumes that it is a sequence of map entries and casts each element to Map$Entry.
So, here it'll be attempting to cast your Longs to Map$Entry.
into is implemented on top of conj.
(into {} ...) ;; equivalent to (below)
(-> {}
(conj (map #(Long/parseLong %) ["1" "2"]) ;; produces the same exception
(conj (map #(Long/parseLong %) ["3" "4"]))
conj expects either a map, a map entry or a two-element vector. Consider this excerpt from http://clojure.org/data_structures#toc17:
conj expects another (possibly single entry) map as the item, and returns a new map which is the old map plus the entries from the new, which may overwrite entries of the old. conj also accepts a MapEntry or a vector of two items (key and value).

(not= (type `(1)) (type `(1 2))) ;; Why? (single element list, syntax-quote, Cons, PersistentList)

I see this behavior in Clojure 1.2.1:
user=> (type '(1 2))
clojure.lang.PersistentList
user=> (type `(1 2)) ;; notice syntax-quote
clojure.lang.Cons
user=> (type '(1))
clojure.lang.PersistentList
user=> (type `(1))
clojure.lang.PersistentList
I expected `(1) to be a Cons just like `(1 2) is.
I also tried:
user=> (type (cons 1 nil))
clojure.lang.PersistentList
user=> (type (cons 1 `()))
clojure.lang.Cons
user=> (type (cons 1 '()))
clojure.lang.Cons
user=> (type (cons 1 []))
clojure.lang.Cons
So what is the reason for `(1) and (cons 1 nil) to be PersistentLists?
Like amalloy says, you shouldn't program against those exact types but against the seq abstraction.
However, I think I can take a guess at the reason. The Clojure forms that produce a PersistentList ultimately call RT.java, specifically the cons(Object x, Object coll) method. It begins with a pretty odd check: if(coll == null) return new PersistentList(x), after which it creates a Cons object if that check doesn't pass. If you look at earlier versions of the code, you can find this:
static public IPersistentCollection cons(Object x, IPersistentCollection y) {
if(y == null)
return new PersistentList(x);
return y.cons(x);
}
So in an earlier version of the function, the call was dispatched to the cons method of the second argument, so the case when the second argument was null (i.e. nil in Clojure) needed special handling. Later versions don't do that dispatching (or actually do it but in a different way, presumably to support a larger variety of collection types), but the check has been retained since it does not break any correctly written code.
If you care about the difference, your program is incorrect. They're both seqs, in the sense that (seq? x) returns true; the rest is implementation details you shouldn't depend on.