How can I make a spec that accepts only sequential (i.e. order-preserving) collections?
For example
cljs.user=> (s/def ::path (s/+ number?))
:cljs.user/path
cljs.user=> (s/explain ::path [])
val: () fails spec: :cljs.user/path predicate: number?, Insufficient input
:cljs.spec.alpha/spec :cljs.user/path
:cljs.spec.alpha/value []
cljs.user=> (s/explain ::path [1 2 3])
Success!
That's as expected, but in the same time, pay attention to the order
cljs.user=> #{1 2 3}
#{1 3 2}
cljs.user=> (s/explain ::path #{1 2 3})
Success!
And that doesn't appear to make any sense. So a secondary question:
Why sequence-related expressions (cat, *, +, ?) in spec accept sequence-breaking collections?
UPD I've messed up sequential/ordered distinction in original question. Cleaned up terminology.
How can I make a spec that accepts only order-preserving collections?
There's a clojure.core predicate function sorted? that will return true for collections that implement Sorted.
(sorted? (sorted-map))
=> true
It doesn't return true for collections with contents that happen to be sorted but don't implement Sorted:
(sorted? [1 2 3])
=> false
You can use arbitrary predicate functions in specs, so you could define a function that returns true for collections with sorted contents:
(defn ordered? [coll]
(or (empty? coll) (apply <= coll)))
(ordered? [1 2 3])
=> true
Then you can use s/and to combine this predicate with your regex spec:
(s/def ::path (s/and (s/+ number?)
ordered?))
(s/explain ::path [1 2 3])
Success!
=> nil
(s/explain ::path #{1 2 3})
val: [1 3 2] fails spec: :playground.so/path predicate: ordered?
=> nil
Specs for sequences (regex specs) should not match ordered, that is sequential collections. This was a bug that has been fixed in current versions of spec, see CLJ-2183.
In Clojure 1.10.0-RC5 the results are as expected:
(s/conform ::path [1 2 3]) ; => [1 2 3]
(s/conform ::path #{1 2 3}) ; => :clojure.spec.alpha/invalid
(s/explain ::path #{1 2 3})
;; #{1 3 2} - failed: (or (nil? %) (sequential? %)) spec: :user/path
You can see in the last line that regex specs now only match values that are sequential?.
Related
I am still trying to understand better how to work with transducers in clojure. Here, I am interested in applying aggregating transducers, such as the ones in https://github.com/cgrand/xforms, but reporting at each step the intermediate values of the computation.
For instance, the following expression
(sequence (x/into #{}) [1 2 3])
yields (#{1 2 3}), which is only the final value of the reduction. Now, I would be interested in an transducer xf-incremental that given something like
(sequence (comp xf-incremental (x/into #{})) [1 2 3])
yields (#{1} #{1 2} #{1 2 3}).
The reason why I am interested in this is that I want to report intermediate values of a metric that aggregates over the history of processed values.
Any idea how can I do something of the sort in a generic way?
EDIT: Think of (x/into #{}) as an arbitrary transducer that aggregates results. Better examples could be x/avg or (x/reduce +) where I would expect
(sequence (comp xf-incremental x/avg) [1 2 3])
(sequence (comp xf-incremental (x/reduce +)) [1 2 3])
to return (1 3/2 2) and (1 3 6) respectively.
EDIT 2: another way of phrasing this is that I want a transducer that performs a reducing function and returns the accumulator at each step, which also can reuse all the available transducers so I do not need to rewrite basic functionalities.
Solution using clojure.core/reductions
You don't need a transducer to perform the computation that you are asking for. The function you are looking for to see all the intermediate results of reduce is called reductions and you provide it with conj and an empty set as arguments:
(rest (reductions conj #{} [1 2 3]))
;; => (#{1} #{1 2} #{1 3 2})
rest removes the first empty set, because that was the output you requested in the original question.
The function that builds up the result here is conj, lets refer to it as a step function. A transducer is a function that takes a step function as input and returns a new step function as output. So if we want to combine reductions with a transducer, we can just apply the transducer to conj:
(def my-transducer (comp (filter odd?)
(take 4)))
(dedupe (reductions (my-transducer conj) #{} (range)))
;; => (#{} #{1} #{1 3} #{1 3 5} #{7 1 3 5})
dedupe is there just to remove elements that are equal to preceding elements. You can remove it if you don't want to do that. In that case you get the following, because that is how the filtering transducer works:
(reductions (my-transducer conj) #{} (range)))
;; => (#{} #{} #{1} #{1} #{1 3} #{1 3} #{1 3 5} #{1 3 5} #{7 1 3 5})
Transducer-based solution using net.cgrand.xforms/reductions
Apparently, there is also a transducer version of reductions in the xforms library, which is closer to your initial code:
(require '[net.cgrand.xforms :as xforms])
(rest (sequence (xforms/reductions conj #{}) [1 2 3]))
;; => (#{1} #{1 2} #{1 3 2})
This xforms/reductions transducer can be composed with other transducer using comp to for example filter odd numbers and taking the first four of them:
(sequence (comp (filter odd?)
(take 4)
(xforms/reductions conj #{}))
(range))
;; => (#{} #{1} #{1 3} #{1 3 5} #{7 1 3 5})
In this case, you don't need dedupe. It is also possible to use other step functions with xforms/reductions, e.g. +:
(sequence (comp (filter odd?)
(take 10)
(xforms/reductions + 0)
(filter #(< 7 %)))
(range))
;; => (9 16 25 36 49 64 81 100)
user=> (map inc #{1 2 3})
(2 4 3)
user=> (into #{} (map inc #{1 2 3}))
#{4 3 2}
Is there a way to apply a function to a set and return a set directly?
A slightly more generic way to do this is to use empty:
(defn my-map [f c]
(into (empty c)
(map f c)))
This yields following results:
(my-map inc #{1 2 3}) ;; => #{2 3 4}
(my-map inc [1 2 3]) ;; => [2 3 4]
(my-map inc '(1 2 3)) ;; => (4 3 2)
It would work for other persistent collections as well.
As Alex said, fmap from algo.generic provides this function, although if you look at the source it's doing exactly the same as your code. I'd recommend just putting your function in a util namespace in your code, it's probably not worth pulling in a whole library for one function.
With Clojure 1.7.0 (still in beta) you can do this using a transducer:
(into #{} (map inc) #{1 2 3})
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
It gives me a ArrayMap as I code
(class (hash-map))
But it comes out a HashMap when I code:
(class (hash-map "" ""))
Question is "How can I create an empty hash-map"?
Another possibility is to use pre-defined EMPTY field:
user=> (clojure.lang.PersistentHashMap/EMPTY)
{}
In my opinion it is better shows your intent.
You can create empty hash-map like this:
(. clojure.lang.PersistentHashMap create {})
(clojure.lang.PersistentHashMap/create {})
(clojure.lang.PersistentHashMap/EMPTY)
You can check the source code of hash-map:
user=> (source hash-map)
(defn hash-map
"keyval => key val
Returns a new hash map with supplied mappings. If any keys are
equal, they are handled as if by repeated uses of assoc."
{:added "1.0"
:static true}
([] {})
([& keyvals]
(. clojure.lang.PersistentHashMap (create keyvals))))
As you can see in the code, if you don't provide arguments, hash-map function returns {}, which is the instance of PersistentArrayMap.
If you really need the instance of empty PersistentHashMap, you can create it with the following code:
(. clojure.lang.PersistentHashMap create {})
You can check the class of created instance:
user=> (class (. clojure.lang.PersistentHashMap create {}))
clojure.lang.PersistentHashMap
user=> (class (clojure.lang.PersistentHashMap/create {}))
clojure.lang.PersistentHashMap
user=> (class (clojure.lang.PersistentHashMap/EMPTY)) ;; om-nom-nom's : much simpler
clojure.lang.PersistentHashMap
But, I'm not sure that doing this is good or necessary. Perhaps you code shouldn't depend on specific implementation class.
You shouldn't really need to worry about this. The runtime makes a judgement on the best implementation to use. PersistentArrayMap is preferred (ie. it's more efficient in time and space) for a small number of key/value pairs, but promotion to PersistentHashMap happens once the kv limit of 8 is crossed, see the relevant code for details
*clojure-version*
{:major 1, :minor 5, :incremental 1, :qualifier nil}
; map declared with {} with 8 kv pairs is ArrayMap
(type {:a 1 :b 2 :c 3 :d 4 :e 5 :f 6 :g 7 :h 8})
=> clojure.lang.PersistentArrayMap
; map declared with {} with 9 kv pairs is HashMap
(type {:a 1 :b 2 :c 3 :d 4 :e 5 :f 6 :g 7 :h 8 :i 9})
=> clojure.lang.PersistentHashMap
; assoc'ing 1 kv pairs into an ArrayMap is an ArrayMap (oddly)
(type (-> {:a 1 :b 2 :c 3 :d 4 :e 5 :f 6 :g 7 :h 8}
(assoc :i 9)))
clojure.lang.PersistentArrayMap
; assoc'ing 2 kv pairs into an ArrayMap is an HashMap
(type (-> {:a 1 :b 2 :c 3 :d 4 :e 5 :f 6 :g 7 :h 8}
(assoc :i 9)
(assoc :j 10)))
clojure.lang.PersistentHashMap
Given a map {:a 1 :b [2,3]}, is there a built-in function which would return the sequence (:a 1 :b [2,3]).
The use case is applying an options map to a function which does map-destructured binding on the remainder of an argument list. Here's an example of this in core.cache. Here's a contrived example to illustrate:
(defn make-car [& {:as options}] (assoc options :car true))
(make-car :color "red" :speed "fast")
; => {:car true, :speed "fast", :color "red"}
Now if we want to manage the options separately and apply them to the function, we have a problem:
(def options {:color "red" :speed "fast"})
(apply make-car options)
; => {:car true, [:speed "fast"] [:color "red"]}
...because of course the seq of a map is a sequence of its key-value pairs. This is the best I've come up with:
(apply make-car (interleave (keys options) (vals options)))
; => {:car true, :speed "fast", :color "red"}
This is pretty awful. I know I could just make my own function to do this, but I'm surprised I haven't found something built-in. If there isn't something built-in, then I'd probably want to avoid destructuring argument lists like this in library code.
How about this:
(reduce concat {:a 1 :b [2,3]})
(:a 1 :b [2 3])
Update based on the comment from amalloy.
Apply is more efficient (at least in 1.4), and achieves the same result!
(apply concat {:a 1 :b [2,3]})
(:a 1 :b [2 3])