I'm trying get a clojure function to detect if the value passed is a map.
For example,
user=> (if-map {:foo 1}) ;Should return true
true
user=> (if-map "hello") ;Returns false
false
Is there a pre-built function serving this already?
Yes, map? is the inbuilt function
(map? {:a 1})
=> true
(map? [1])
=> false
Related
Write a function which, given a key and map, returns true if the map contains an entry with that key and its value is nil.
Solution I came across:
#(nil? (get %2 % true))
Can someone please explain the use of true in
(get %2 % true) ?
Thank you!
that's a default value that will be returned in the case of absence of the key
;; key exists
(get {:a 1} :a 2)
#=> 1
;; key doesn't exist (default value is returned)
(get {:a 1} :b 2)
#=> 2
;; key exists and it's value is nil
(get {:a nil} :a 2)
#=> nil
;; key doesn't exist, nil is returned
(get {:a 1} :b)
#=> nil
some docs could be found here
https://clojuredocs.org/clojure.core/get
so the idea is that (get {:a 1} :b) will always return nil because key doesn't exist. In this case (nil? (get {:a 1} :b)) will return true, which is not what we want. That's why adding this default value is necessary. So nil will be returned only in the case when the actual value is nil.
The value true is not special here. 85 would work just as well: any value other than nil fixes the problem.
For some reason the below spec does say that false isn't a valid ::a-thing even though it is part of the given set.
(require '[clojure.spec.alpha :as spec])
(spec/def ::a-thing #{:a :b :c false})
(spec/valid? ::a-thing :a) ; => true
(spec/valid? ::a-thing :d) ; => false
(spec/valid? ::a-thing false) ; => false
This is nothing to do with spec, and everything to do with how sets behave as functions. You will get similar misunderstandings whenever you use a set as a function to test for membership.
When you pass spec a function, it uses it as a predicate. Sets are functions, as is anything else that implements clojure.lang.IFn. As functions, sets behave as identities on their members. All else follows. Sets are in no way treated specially by spec.
It turns out that falsey things aren't allowed in sets given to Spec
as it uses the set itself as a function to check for membership rather than
the contains? function. As we can see below a set will return the
given argument if it is a member of the set and nil otherwise.
(#{:a :b :c false} :a) ; => :a
(#{:a :b :c false} false) ; => false
(#{:a :b :c false} :d) ; => nil
This of course is the cause of the misunderstanding.
We have to manually wrap the set in a contains ourselves in order to get the spec working properly.
(spec/def ::a-thing #(contains? #{:a :b :c false} %))
As only symbols and collections support metadata is there a standard way for checking if a value supports metadata? eg.
(can-have-metadata? value)
At the moment I am checking if the value is an instance of IObj, but curious if there is a better way.
user> (defn meta-available? [x]
(instance? clojure.lang.IMeta x))
#'user/meta-available?
user> (meta-available? 1)
;=> false
user> (meta-available? "abc")
;=> false
user> (meta-available? [1 2 3])
;=> true
user> (meta-available? {:a 1})
;=> true
What is the difference between the functions seq? sequential? and coll?
I found some information scattered throughout the internet, but I think it would be better to centralize that information here.
seq? is a predicate that returns true if it's argument implements ISeq interface, which is to say it provides the methods first,rest,cons. See http://clojure.org/sequences.
(seq? [1 2])
false
(seq? (seq [1 2]))
true
sequential? is a predicate that returns true if it's argument implements Sequential interface. Sequential is a marker interface (no methods) and is a promise that the collection can be iterated over in a defined order (e.g. a list, but not a map).
(sequential? [])
true
(sequential? {})
false
coll? is a predicate that returns true if its argument implments IPersistentCollection. So for example the clojure data structures would return true, whereas native java data structures would not:
(coll? {:a 1})
true
(coll? (java.util.HashMap.))
false
seq? is true for any sequence.
sequential? is true for any sequential (not associative)
collection.
coll? is true for any Clojure collection.
seq? implies sequential? implies coll?
=> ((juxt seq? sequential? coll?) ()) ; [true true true]
=> ((juxt seq? sequential? coll?) []) ; [false true true]
=> ((juxt seq? sequential? coll?) #{}); [false false true]
Inaccurate: sequential? is related to the others purely by convention - see Kevin's answer.
Basically...
=> (atom? 5)
CompilerException java.lang.RuntimeException: Unable to resolve symbol: atom? in this context, compiling:(NO_SOURCE_PATH:1)
=> (atom? /a)
RuntimeException Invalid token: /a clojure.lang.Util.runtimeException (Util.java:156)
RuntimeException Unmatched delimiter: ) clojure.lang.Util.runtimeException (Util.java:156)
=> (atom? "hello world")
CompilerException java.lang.RuntimeException: Unable to resolve symbol: atom? in this context, compiling:(NO_SOURCE_PATH:1)
So does anyone know what's happening??
I am using Eclipse Juno 4.2, the CounterClockwise plugin.
What's called an atom in Clojure is something completely different than what's called an atom in other Lisps. In classic Lisp an atom is a single value, defined as being not null or not a cons cell (pair):
(define (atom? x)
(not (or (pair? x)
(null? x ))))
In Clojure an atom is a concurrency reference type. Atoms in Clojure can be either single-valued or collections/sequences, where updating (mutable state change) is guaranteed to happen atomically.
In Clojure there's far more reference types than the cons list in Lisp, and there's all the Java interop collection types to be reckoned with. That makes it hard to define a check on single-values.
If you do want to, the simplest check is to see if something can be counted. Looking at (source counted), it references clojure.lang.RT/count and countFrom. There, several classes / interfaces are specified, which I included in the following function:
=> (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]))))
=> (map single-valued? [1 "foo" \a 'x true not nil])
(true true true true true true false)
=> (map single-valued? ['(1 2 3 4)
[1 2 3 4]
{:a 1 :b 2}
#{1 2 3 4}
(seq [1 2 3 4])
(seq {:a 1 :b 2})
(seq "foo")
(int-array [1 2 3 4])
(seq [])])
(false false false false false false false false false)
Since (seq []) evaluates to nil it's not considered single-valued. Of course, java objects with multiple fields, as well as Clojure deftypes / defrecords will register as such, even though they're composite objects.
I suspect you are confusing a clojure atom with an atom in something like scheme.
In scheme an atom is a fundamental unit.
In clojure an atom is one of clojure's reference types (like ref and var) that can be updated atomically.
This fits nicely with clojure's concurrency model.
e.g.
user> (def a (atom '(1 2 3)]); create an atom with value (1 2 3)
user> #a ; look up (deference) the atoms value
(1 2 3)
user> (swap! a (fn [v] (map inc v))) ; add 1 to each element, v is the
; old value of the atom. other threads will
; see the three values in a change atomically
user> #a
(2 3 4)
user> (reset! a '(5 10 15))
user> #a
(5 10 15)
atom? is not a function.
You could use
(def x (atom 5))
(instance? clojure.lang.Atom x)
You can create atom? function like this:
(defn atom? [x]
(not (coll? x))
)
The complement function returns the opposite of any predicate passed to it as argument, so you can make a atom? with it:
(defn atom?
[x]
((complement coll?) x))
(atom? []) ;=> false
(atom? ()) ;=> false
(atom? {}) ;=> false
(atom? 4) ;=> true