Hello,
I’m trying to learn spec and during my experiments, I encountered a problem that hopefully someone will help me solve.Here it is :
I want to use :pre
and :post
conditions on a function that will receive a list of strings, and returns a list of capitalized string (not very useful, but good for illustration). So I wrote this :
(s/def :exp/username string?)
(s/def :exp/players (s/coll-of :exp/username
:kind list?))
(defn capitalize [players]
{:pre [(s/valid? :exp/players players)]
:post [(s/valid? :exp/players %)]}
(map str/capitalize players))
(defn start []
(capitalize '("bob", "alice", "tom")))
With the above example, the :post
validation fails. I assume this is because capitalize function actually returns a LazySeq and not a PersistentList, list? predicates returns false.
Is it correct ?
Assuming this is correct, I tried to use doall because I understood it would consume the entire sequence and so, maybe, would return a PersistentList, but from what I could see it doesn’t change the list type.
Eventually I force type conversion applying list
:
(defn capitalize [players]
{:pre [(s/valid? :exp/players players)]
:post [(s/valid? :exp/players %)]}
(apply list (map str/capitalize players))) ;; <--
And then it works… but I have doubts :
- is it the good way to proceed ?
- is it a good idea a lazy sequence in the first place ? I assume there is no other way but consume the entire sequence, which cancels the benefit of lazyness
- should I use
seq?
instead oflist?
Any clarification and advice on this subject will be very welcome.
Thanks in advance
ciao