So there's list?, seq?, vector?, map? and so on to determine what type of collection the argument is.
What's a good way of telling the difference between
a map (i.e. something that contains key-value pairs)
a collection (i.e. something that contains values)
a non collection value like a string.
Is there a better way than
#(or (seq? %) (list? %) etc)
using seq? is about as concise and clean as it gets.
clojure.contrib.core defines:
seqable?
function
Usage: (seqable? x)
Returns true if (seq x) will succeed, false otherwise.
http://clojure.github.com/clojure-contrib/core-api.html
it does what you proposed with one big or statement of
already a seq
an instance of clojure.lang.Seqable
nil
instance of Iterable
an array
a string
instance of java.util.Map
Let's not forget about sequential?:
user=> (sequential? [])
true
user=> (sequential? '())
true
user=> (sequential? {:a 1})
false
user=> (sequential? "asdf")
false
The function seq right now does only this:
(. clojure.lang.RT (seq coll))
In RT.java in the latest version of Clojure, you'll find:
static public ISeq seq(Object coll){
if(coll instanceof ASeq)
return (ASeq) coll;
else if(coll instanceof LazySeq)
return ((LazySeq) coll).seq();
else
return seqFrom(coll);
}
static ISeq seqFrom(Object coll){
if(coll instanceof Seqable)
return ((Seqable) coll).seq();
else if(coll == null)
return null;
else if(coll instanceof Iterable)
return IteratorSeq.create(((Iterable) coll).iterator());
else if(coll.getClass().isArray())
return ArraySeq.createFromObject(coll);
else if(coll instanceof CharSequence)
return StringSeq.create((CharSequence) coll);
else if(coll instanceof Map)
return seq(((Map) coll).entrySet());
else {
Class c = coll.getClass();
Class sc = c.getSuperclass();
throw new IllegalArgumentException("Don't know how to create ISeq from: " + c.getName());
}
}
An ASeq or a LazySeq is already a seq. A Seqable is something that knows how to return a seq of itself.
That leaves things like Java core classes, which should be seqable but which Clojure can't alter to add a seq method. Those are currently hard-coded into this list. I wouldn't be surprised if the implementation changed someday, maybe using protocols to extend the Java core classes instead?
All seqables implement clojure.lang.Seqable marker:
(instance? clojure.lang.Seqable x)
Clojure 1.9 provides seqable?
Related
I am taking an example from the clojure site.
(defmulti foo class)
(defmethod foo ::collection [c] :a-collection)
(defmethod foo String [s] :a-string)
(foo [])
:a-collection
(foo (java.util.HashMap.))
:a-collection
(foo "bar")
:a-string
This functionality is cool. I'm trying to understand the technical reasons why this is superior to an instanceof based implementation in (for example) java. It seems to me essentially equivalent in function with nicer syntax.
public <T> String foo(final T t) {
if (t instanceof Collection) {
return "a-collection";
} else if (t instanceof String) {
return "a-string";
} else {
throw new IllegalArgumentException("Undefined - no available dispatch");
}
}
What are the reasons why multimethods are considered a great alternative to visitor pattern based double dispatch while instanceof is not when they seem like they're essentially doing the same thing?
One of the benefits discussed in the comments is that the defmulti and defmethod can be done in different files, by different users. An excellent example is Clojure's own print-method multi-method.
From the docs, we see how we can define a custom print-method for a new record type we create:
(deftype XYZ [])
; without custom print-method defined:
user=> (prn (XYZ.))
#<XYZ user.XYZ#2670d85b>
; Note, this hooks into the pre-existing `(defmulti print-method ...)`
(defmethod print-method XYZ [v ^java.io.Writer w]
(.write w "<<-XYZ->>"))
; with print-method
user=> (prn (XYZ.))
<<-XYZ->>
So while it has similarity to a giant cond statement, it is more flexible & cleaner.
(map (fn [x]
(let [username (or (:f_username x) nil)
sites_names (SITES-NAMES username)
x (assoc x :sites sites_names)]
x)) my-rows)
In the code above: SITES-NAMES gives me an arity exception. However
if I call it (SITES-NAMES "theuser") it works. Why is this the case
if username evaluates as an example to "theuser".
I don't know why this is happening, but here are a few tips:
1) Make your anonymous function a top-level function, as such:
(defn add-site [site-names {:keys [f-username] :as x}]
(assoc x :sites (get site-names f-username)))
Notice how I name the vars, refer to https://github.com/bbatsov/clojure-style-guide for more info on naming and other neat stuff.
2) Now you can change your call to map with
(map (partial add-site site-names) my-rows)
This lets you play around with the add-site function at the REPL like so:
user> (add-site {"hector" "www.hector.com"} {:f-username "hector"})
;; => {:f-username "hector", :sites "www.hector.com"}
You might want to read this as well:
https://stuartsierra.com/2015/08/10/clojure-donts-redundant-map
So I am trying to write the below in clojure (Assume all methods below return boolean)
def some_method(a, b)
if (call_this_method() )
then_call_this_method()
else
new_method()
end
What I got was this:
(defn some-method [a b]
(if (call_this_method)
:then (then-call-this-method)
:else (new-method)))
I am pretty new to clojure so am not sure if this feels like the correct manner to solve this. Is there a different approach?
if basically takes 3 params, [condition what-to-run-if-true optional-run-if-false]
(defn some-method
"My function does ..."
[ a b ]
(if (call-this-method)
(then-call-this-method)
(new-method)))
You can use if in clojure as well
(if test then-code else-code)
Or cond which is more like switch
(cond
test-A run-if-A
test-B run-if-B
...
:else else-code)
And if you wanted to do something like
if(foo) bar;
Then you would write
(when foo bar)
I have the following record type that I am trying to test:
(defrecord FirstOrderState [datum matrix]
State
;; implementation goes here ...
)
I am trying to branch based on the above type, but am not getting the results I need
(def state (->FirstOrderState datum matrix))
(= (type state) composer.algorithm.markov.state.FirstOrderState)
=> false
However, looking at the type of state confirms that it should match:
(type state)
=> composer.algorithm.markov.state.FirstOrderState
This seems like it should work, as a similar check results in true:
(= (type []) clojure.lang.PersistentVector)
=> true
What is it that I am missing here? Using the below hack provides a solution, but not very elegant:
(= (str (type state)) (str composer.algorithm.markov.state.FirstOrderState))
=> true
My first guess would be that you have reloaded the namespace containing the definition of the record type and that state is defined elsewhere (possibly at the REPL), and so composer.algorithm.markov.state.FirstOrderState now refers to a different class from the one it used to at the time when state was created.
Demo at the REPL:
user=> (defrecord Foo [])
user.Foo
user=> (def foo (->Foo))
#'user/foo
user=> (= (type foo) Foo)
true
user=> (defrecord Foo [])
user.Foo
user=> (= (type foo) Foo)
false
I recently asked why interfaces and protocols could be incompletely implemented in clojure:
user=> (defprotocol P (foo [self]))
P
user=> (extend-type Long P)
nil
user=> (extends? P Long)
true
user=> (foo 1)
IllegalArgumentException No implementation of method: :foo of protocol: #'user/P found for class: java.lang.Long clojure.core/-cache-protocol-fn (core_deftype.clj:527)
and was told that this was for interop reasons and that it wouldn't be a problem in practice. Sure.
But apparently extends? really tells me nothing about the relationship between a protocol and a class: just as (extends? P C) does not imply that I can call foo on objects of class C, (not (extends? P C)) does not imply that I cannot call foo on objects of class C:
user=> (defprotocol P (foo [self]))
P
user=> (extend-type Object P (foo [self] 1))
nil
user=> (extends? P Long)
false
user=> (foo 1)
1
Now I am very confused about what information extends? is supposed to give me... satisfies?, on the other hand, handles the second case correctly, but not the first one.
When in doubt check the code :). The implementation of extends? is this:
(defn extends?
"Returns true if atype extends protocol"
{:added "1.2"}
[protocol atype]
(boolean (or (implements? protocol atype)
(get (:impls protocol) atype))))
So it just check if the atype has been extended by the protocol and it doesn't mean it has implemented all the methods of the protocol.
The :impls is a map where key is the type that extended the protocol and the value is map which has the methods implementation of the protocol for the type.
user=> (defprotocol hello (a [self]))
hello
user=> (:impls hello)
nil
user=> (extend-type String hello)
nil
user=> (:impls hello)
{java.lang.String {}}
user=> (extend-type String hello (a [self] 10))
nil
user=> (:impls hello)
{java.lang.String {:a #<user$eval613$fn__614 user$eval613$fn__614#1d978ea>}}
On the other hand to satisfies? you need to pass the object on which you want to check for protocol and not the type as in case of extends? So if you look at satisfies? code it is a bit more complex then extends as it has to check the base classes of the object being passed for being extended by protocol. But both the functions just check whether there the type (or base types) has extended the protocol or not AND they don't check if you have actually implemented the protocol methods or not.