what’s the proper way to check if a value is a sequence? seq?
doesn’t work on vectors
seq?
tests whether something is a seq (not a sequence). And a vector is not a seq. It depends on exactly what types of data you're trying to select for, but I suspect sequential?
is probably what you want @grazfather
FYI:
user=> (doc seq?)
-------------------------
clojure.core/seq?
([x])
Return true if x implements ISeq
nil
user=> (doc sequential?)
-------------------------
clojure.core/sequential?
([coll])
Returns true if coll implements Sequential
nil
user=> (doc seqable?)
-------------------------
clojure.core/seqable?
([x])
Return true if the seq function is supported for x
nil
that works. Why are lists seqs but vectors are not?
I thought seq just meant an ordered collection
i guess not. How is ISeq different from Sequential, then?
ISeq
is this interface: https://github.com/clojure/clojure/blob/master/src/jvm/clojure/lang/ISeq.java
Sequential
is a "marker" interface -- it has no methods.
Right, I guess I just thought that vector would implement that interface
user=> (->> [1 2 3] type ancestors (sort-by str))
(clojure.lang.AFn clojure.lang.APersistentVector java.lang.Object clojure.lang.Associative clojure.lang.Counted clojure.lang.IEditableCollection clojure.lang.IFn clojure.lang.IHashEq clojure.lang.IKVReduce clojure.lang.ILookup clojure.lang.IMeta clojure.lang.IObj clojure.lang.IPersistentCollection clojure.lang.IPersistentStack clojure.lang.IPersistentVector clojure.lang.IReduce clojure.lang.IReduceInit clojure.lang.Indexed clojure.lang.Reversible
clojure.lang.Seqable ; vector is seqable (you can call seq on it)
clojure.lang.Sequential ; vector is sequential
java.io.Serializable java.lang.Comparable java.lang.Iterable java.lang.Runnable java.util.Collection java.util.List java.util.RandomAccess java.util.concurrent.Callable)
Clojure tries to avoid providing inefficient ways to access data. Vectors are efficient for conj
at the end, lists are efficient for conj
at the start, which is what cons
does.
cool. thank you!
and til ancestors
So vector has peek
and pop
instead of first
and next
:
user=> (peek [1 2 3])
3
user=> (pop [1 2 3])
[1 2]
(and they operate on the end of the vector, not the start)
first
works on vectors
Right, but it calls seq
first and so you are coercing the vector into a sequence.
ah
map
etc also work on vector by coercing it to a sequence first.
alright. Thank you. I see seq?
used a lot to test if something is a sequence, I was pretty suprised to see it not work on vectors. What’s the proper way to test that a value is iterable?)
It depends what you mean by "iterable". Vectors implement java.lang.Iterable
but I suspect that's not what you mean?
I agree. I would say that if code is using seq?
it is either doing something very specific or it is wrong 🙂
I mean an ordered collection
ok
but seq
crashes if its a different type like true
Sounds like Sequential
then.
works for me
There's seqable?
to test for things that can be seq
'd.
user=> (seqable? true)
false
alright, thanks again
Although maps and sets aren't sequential?
, but they are seqable?
> (sequential? {})
false
> (sequential? #{})
false
> (seqable? {})
true
> (seqable? #{})
true
user=> (for [coll [(list 1 2 3) [1 2 3] #{1 2 3} {1 2, 3 4}] f '[seq? sequential? seqable?]] [((resolve f) coll) f coll])
([true seq? (1 2 3)] [true sequential? (1 2 3)] [true seqable? (1 2 3)] [false seq? [1 2 3]] [true sequential? [1 2 3]] [true seqable? [1 2 3]] [false seq? #{1 3 2}] [false sequential? #{1 3 2}] [true seqable? #{1 3 2}] [false seq? {1 2, 3 4}] [false sequential? {1 2, 3 4}] [true seqable? {1 2, 3 4}])
user=> (clojure.pprint/pp)
([true seq? (1 2 3)]
[true sequential? (1 2 3)]
[true seqable? (1 2 3)]
[false seq? [1 2 3]]
[true sequential? [1 2 3]]
[true seqable? [1 2 3]]
[false seq? #{1 3 2}]
[false sequential? #{1 3 2}]
[true seqable? #{1 3 2}]
[false seq? {1 2, 3 4}]
[false sequential? {1 2, 3 4}]
[true seqable? {1 2, 3 4}])
This might be helpful: https://clojure.org/reference/sequences
And also: https://clojure.org/reference/data_structures#Collections
Seqs are a logical list abstraction
Vectors (and maps and sets etc) can provide a seq view (a logical list) over those collections
I realise I'm not too sure what functions I can use to combine 2 lists together but anyway I have a list like so ...
`((171) (0 0 0 0 0 0)
(147) (0 0 0 0)
(183) (0 0 0 0 0 0 0))
how do I transform the list into something like
`((171 0 0 0 0 0 0)
(147 0 0 0 0)
(183 0 0 0 0 0 0 0))
Like to merge pairs of elements successively(Im not a clojure expert) maybe this way?
(->> `((171) (0 0 0 0 0 0)
(147) (0 0 0 0)
(183) (0 0 0 0 0 0 0))
(partition-all 2)
(map (fn [[left right]]
(concat left right))))
Right! That's definitely 1 way 🙂
Transducer version (into [] (comp (partition-all 2) (map flatten)) [[1 2] [3 4] [5 6] [7 8]])
@zackteo as a general tip, stick to vectors rather than lists or sequences unless there’s a specific need; easier to reason about IMO
Is there a way to make Clojure always print seqs as a literal? I am copy-pasting a lot of output into the REPL and I always forget to add '
in front of seqs. (`(:hi :there)` triggers an error as you know.)
You might be able to simply quote everything you print. Quoted maps and vectors read back "correctly" too. Are you just printing random stuff with all the print functions? Or are you using tap?
I am not using tap. I've just heard the term. How is it applicable here?
You might be able to add your quotes with add-tap https://clojuredocs.org/clojure.core/add-tap
Note that flatten
recursively flattens nested sequences - I would go with (map #(apply concat %))
Prefer vectors where possible
mapv, vec functions come in handy
I should make my own print that uses Specter or some such to find and turn seqs into vecs.
But sometimes I want the colls to actually be seqs 🙂
Almost everything you can do with lists/seqs you can do with vectors, but you avoid the copy paste problem
(concat '(171) '(0 0 0 0 0 0)) ;; '(171 0 0 0 0 0 0)
I'd like to make selmer.parser/render
join lists of strings before rendering, but leave strings as is:
(render "{{input}}" {:input ["a.txt" "b.txt"]}) => "a.txt b.txt"
(render "{{input.1}}" {input ["a.txt" "b.txt"]}) => "a.txt"
Currently the first would print "["a.txt" "b.txt"]"
. I'd like to avoid having to call {{input|join\" \"}}
or do it implicitly.This is the code selmer
uses to render:
(defn render-template [template context-map]
" vector of ^selmer.node.INodes and a context map."
(let [buf (StringBuilder.)]
(doseq [^selmer.node.INode element template]
(if-let [value (.render-node element context-map)]
(.append buf value)
(.append buf (*missing-value-formatter* (:tag (meta element)) context-map))))
(.toString buf)))
And node is
(deftype TextNode [text]
INode
(render-node [this context-map]
(str text))
(toString [_]
(str text)))
Does this make it possible to inject my desired code or override the existing implementation? Never made or extended protocols before. https://www.braveclojure.com/multimethods-records-protocols/.(deftype L [l]
clojure.lang.IPersistentCollection
(toString [self] (str/join " " l)))
(render "all: {{lst}} one: {{lst.1}}" {:lst (L. [1 2 3])})
"all: 1 2 3 one: "
Now I need to find out how to implement whichever method is needed to pick out elements.I have the following deftype
:
(require '[clojure.string :as str])
(deftype L [l]
clojure.lang.IPersistentCollection
(toString [self] (str/join " " l)))
What is the minimal code needed to support get
/index lookups?
(def l (L. [1 2 3]))
(l 0) ;; class user.L cannot be cast to class clojure.lang.IFn
([1 2 3] 0) ;; 1
Taking a step back, and because you’re posting in #beginners - is there a specific reason you’re trying to use deftype apart from pure learning? For real-world problems, I would stay away from them, unless you have a specific reason (usually related to low-level high-performance code)
See my previous two questions immediately above this one 🙂 I need a vec which works like this:
(.toString [1 2 3]) ;; "1 2 3"
Why not just:
(str [1 2 3])
=> “[1 2 3]”
Because I need selmer.parser/render
to behave thusly:
(render "all: {{lst}} one: {{lst.2}}" {:lst [1 2 3]}) => "all: 1 2 3 one: 3"
If I am understanding right, one of your goals is for:
(.toString [1 2 3])
… to output:
“123”
Rather than the current:
“[1 2 3]”"1 2 3"
yes 🙂
Of course,
[1 2 3]
should probably be a custom type of some sort. I do not want to override the toString for all vecs.Yeah… that’s probably not a good idea (global override)
I am 95%+ certain that you’re trying to do this the hard way. There should be no issue pre-processing the input rather than trying to achieve some sort of polymorphism based on types; it is definitely possible in Clojure, but not the recommended way.
In 8+ years in Clojure, I’ve never felt the need to do this (and I’ve done quite some years of OOP before that)
Okay, the alternative I can see is to write my own render-function. Which I am sure would be more work than implementing a dinky type with two methods.
Well, in one case you’re writing something to the effect of: 1. look for vectors in your render fn arguments 2. transform those arguments via (apply str [1 2 3]) => “123” 3. call your render fn In the other, you’re creating a brand new type, which chances are you’re not gonna use anywhere else.
Sorry if I’m misunderstanding something 🙂
From my experience in Clojure, creating a new type of vector just to have a specific custom toString function is VERY uncommon.
If I transform the vector then ""{{input}}""
would give the correct result but not ""{{input.1}}""
(the latter would be a single char).
Can you help me do it instead?
Creating a dink custom type is going to be much less work than rewriting someone else's library.
Actually I don’t know how to do it on top of my head, it’s pretty uncommon; I’ll let you know if I figure it out 🙂
Perhaps I should ask this in the regular Clojure channel. But then I would be cross-posting 😕
Just FYI, you’ll also be creating the vector in a custom way, via a new “constructor” etc
Like in a library like this one: https://github.com/clojure/core.rrb-vector
(but a lib like that has a reason to be a new type because it adds capabilities to a vector that it didn’t have before, rather than just customizing .toString)
I only need an object that supports indexed lookups. That is all. Does not need to be a vector really.
You could define your own print method based on the :type
metadata:
(defmethod print-method ::my-thing
[x writer] (.write writer "hello"))
(print-str
(with-meta [1 2 3]
{:type ::my-thing}))
;; => "hello"
How do I get the internals of selmer
to use my custom print-method?
Here is the line that calls toString
: https://github.com/yogthos/Selmer/blob/master/src/selmer/parser.clj#L105
(It happens within the invocation of .render-node
).
ah.. I didn't realize you needed to override toString tself, not printing
No that is okay. A lot of context was hard to see :)
Perhaps take a look at: https://github.com/clj-commons/potemkin It does a decent job of explaining why what you’re trying to do is not so easy (I believe)… When you say “I just need something that supports indexed lookups” - that’s not a straightforward thing in Clojure; there’s a multitude of ways in Clojure to access things in an “indexed” way: nth, get, first, etc; those are all different functions which work with different protocols, interfaces, etc
This is for maps, but I believe relevant “A Clojure map implements the following interfaces: `clojure.lang.IPersistentCollection`, `clojure.lang.IPersistentMap`, `clojure.lang.Counted`, `clojure.lang.Seqable`, `clojure.lang.ILookup`, `clojure.lang.Associative`, `clojure.lang.IObj`, `java.lang.Object`, `java.util.Map`, `java.util.concurrent.Callable`, `java.lang.Runnable`, and `clojure.lang.IFn`. Between them, there’s a few dozen functions, many with overlapping functionality, all of which need to be correctly implemented.”
But can't I just copy all methods from another implementation and override the few I need?
Starting to think OOP wasn't such a bad idea XD
You definitely can: rrb-vector does it https://github.com/clojure/core.rrb-vector
But instead of doing all of those things, I would just do:
(let [v ["a.txt" "b.txt"]
input {:input-vec v :input-str (apply str v)}]
(render "{{input-str}}" input)
(render "{{input-vec.1}}" input))
And be done with it… I don’t really understand what’s the ceremony here.
(I haven’t tested the code above or used selmer, but I suppose that’s how it would work)
This is in the user-facing part of a language I am writing. So that uglyness won't be hidden away in the internals somewhere, but users would have to write it all the time.
"samtools mpileup -g -f {{file.genome}} {{input.sorted}} | bcftools call -mv - > {{output.1}}"
would suddenly become
"samtools mpileup -g -f {{file.genome}} {{input-str.sorted}} | bcftools call -mv - > {{output-vec.1}}"})
I see; now I understand the reason behind it; Perhaps you might want to look at the “hard” way then; For whatever it’s worth, strings in Clojure do support indexed lookup via (nth…) (nth “123" 0 :not-found) => \1 (nth “123” 42 :not-found) => :not-found
But again, that depends on the implementation of the render library; is it using (nth …) when doing that *.1 magic? I don’t know
I am sorry, there might be some super concise way to achieve what you’re trying to do via deftype, etc but I just don’t know it; I am guessing there isn’t but I would like to be proven wrong;
why not to use for
from the library iteself?
(render "all: {% for item in lst %}{{item}} {% endfor %}one: {{lst.2}}" {:lst [1 2 3]})
this one will give you exactly what you are trying to dois that your actual goal?
if so, you can do that by overriding the print-method
for the type
for creating custom collections, there are a variety of different interfaces you might need to implement to replicate different parts of collection functionality
No; I went on a Java interface/class rabbit hole exploration 🙂 And trying to figure out if there’s a generic “proper” way to do it; or it would involve re-writing everything as protocols;
(in general, I'd say this topic is not a #beginners topic and probably better asked in #clojure instead)
Yes… It stemmed from a #beginners conversation… I agree
That’s what I thought. So the short answer is: no, there’s no “one liner” way to extend vectors….
no
you can see what normal vectors implement for example:
user=> (ancestors clojure.lang.PersistentVector)
#{clojure.lang.IPersistentCollection java.lang.Iterable clojure.lang.Sequential clojure.lang.ILookup clojure.lang.APersistentVector java.util.List java.lang.Runnable java.io.Serializable clojure.lang.Indexed clojure.lang.IPersistentVector java.lang.Comparable clojure.lang.IReduce clojure.lang.Associative clojure.lang.IMeta clojure.lang.IEditableCollection clojure.lang.IObj clojure.lang.IFn java.util.concurrent.Callable clojure.lang.AFn java.lang.Object java.util.Collection java.util.RandomAccess clojure.lang.Reversible clojure.lang.IKVReduce clojure.lang.IHashEq clojure.lang.Counted clojure.lang.Seqable clojure.lang.IReduceInit clojure.lang.IPersistentStack}
Ah, that’s neat to know; never knew of that fn
if you're interested in this topic, I wrote a section in Clojure Applied about it with a picture that maps Clojure api functions to methods in the internal interfaces
you might find https://insideclojure.org/2016/03/16/collections/ helpful too
Very cool, will check it out. Thank you for your input Alex, always the trusted source :clj: 🙂
this is kind of a cool helper function too: https://gist.github.com/semperos/3835392
will create a deftype scaffold with a lot of the necessary stuff for a custom type (you will still need to tailor it appropriately but can help a lot)
Hi 👋,
I'm learning about macros. After doing the basic conditional tutorials, I now want to write some more "advanced" macros to wrap my head around the topic.
My goal is to write a macro that returns a function that combines str/replace
functions.
;; It should later work like this:
((combine-replace #"a" "A" #"b" "B") "ab") => "AB"
I started with the base case
(defmacro combine-replace [x y & xs]
`(fn [s#]
(-> s#
(str/replace ~x ~y))))
((combine-replace #"a" "A") "ab") => "Ab"
what I now want is to "write" (str/replace ~x ~y)
n
times for all pairs in xs
. The generated code should look something like this
(-> s#
(str/replace ~x ~y)
(str/replace ~x2 ~y2)
...)
Currently, I'm sitting on this
(defmacro combine-replace [x y & xs]
`(fn [s#]
(-> s#
(str/replace ~x ~y)
~@(loop [xs# xs]
(when xs#
`(str/replace ~(first xs#) ~(second xs#))
(recur (nnext xs#)))))))
can someone help me to understand what I actually have to do, to make this work?maybe this will hint what your a looking for:
(let [xys [#"1" "2" #"3" "4" #"5" "6"]]
(assert (= (mod (count xys) 2) 0) "Expression must be multiple of 2")
(->> xys
(partition 2)
(map (fn [[left right]]
`(some-fun ~left ~right)))))
you gotta move the xs
handling outside of the syntax unquote:
(defmacro combine-replace [x y & xs]
(let [replaces (for [[x1 y1] (partition 2 xs)]
`(str/replace ~x1 ~y1))]
`(fn [s#]
(-> s#
(str/replace ~x ~y)
~@replaces))))
@paulocuneo good call with the assert
. I forgot that partition
handles odd-count seqs
Thank you both so much 🙏❤️
OK, I seem to be having Java “classpath” problems when trying to load external libraries. Am I doing something wrong?
1. First I add to the :dependencies
section of my project.clj
file.
2. Then I do a lein deps
. It seems to load the files from clojars.
3. Then I add the library line(s) in my (ns … (:require … ))
.
But I get a classpath error: Could not locate ring/middleware/json__init.class, ring/middleware/json.clj or ring/middleware/json.cljc on classpath.
Probably a dumb newbie mistake, but what am I doing wrong? (Images included.) It makes me think that my classpath is missing something.
you don't need to run lein deps
my guess is whatever repl your editor is connected to is either not based on your project.clj, or hasn't been restarted since you added the dependencies
Hey guys, so I'd like to use something datomic like for a desktop application I was building. Apparently datomic is not free software, but there are libraries out there that behave like datomic. What are some of the lesser known options out there? So far I know about... • Datahike • Datascript • Datalevin
@hiredman - You are totally right. I exited completely out of Emacs, and then back in, opened up a REPL, and magic! 🎩 Thanks for your help.
I am just making my first attempts with Clojure (Linux, Spacemacs). Now I would like to use data.json (https://github.com/clojure/data.json) but cannot figure out how to install it. Any help very appreciated.
You need to look up leiningen or tools deps. Here is the guide for the latter: https://clojure.org/guides/deps_and_cli
You need to specify your dependencies in a file of a format specific to each of the tools and then use it to download your dependencies and add them to your class path. They can also do other tasks.
This part here? "To work with this library, you need to declare it as a dependency so the tool can ensure it has been downloaded and add it to the classpath. The readme in most projects shows the name and version to use. Create a deps.edn
file to declare the dependency:"
There are some examples in the text, you can copy the snippets from the data.json page for your deps.edn and your source file
I see this file in /usr/share/clojure. Should I add it there?
No, you create a new one in the folder you are working in
Ok. Let me try.
Still get: Clojure 1.10.3
user=> (ns example
(:require [clojure.data.json :as json]))
Execution error (FileNotFoundException) at example/eval138$loading (REPL:1).
Could not locate clojure/data/json__init.class, clojure/data/json.clj or clojure/data/json.cljc on classpath.
example=>
you need to run clj first so it can setup your classpath
{:paths ["src"]
:deps {cheshire/cheshire {:mvn/version "5.10.0"}
org.clojure/data.json {:mvn/version "1.0.0"}
org.clojure/data.csv {:mvn/version "1.0.0"}}
:aliases {:depstar
{:extra-deps
{seancorfield/depstar {:mvn/version "1.1.104"}}}}}
here is a deps.edn I used for a small project> >clj > Please install rlwrap for command editing or use "clojure" instead.
yep, you need rlwrap too
Cool, now it works:<
Thanks so much!
how would i do the following in clojure (reading a js textbook but can't help myself thinking what the clojure equivalent would look like) ... It finds the first number that is both greater than or equal to 20 and divisible by 7.
for (let current = 20; ; current = current + 1) {
if (current % 7 == 0) {
console.log(current);
break;
}
}
best I could come up with is
(first (filter #(zero? (mod % 7)) (iterate inc 20)))
doesn't "feel" righta literal translation: (loop [current 20] (if (zero? (mod current 7)) current (recur (inc current))))
ah loop recur! i rarely use it. Still looks verbose
(println 21) ?
:rolling_on_the_floor_laughing: love it
regarding verbosity, I can't think of the higher level construct that would reduce the size of the code significantly
in either the filter or the loop version, there's not much noise - every expression does something meaningful
agreed but i feel i'm overlooking something take, some, take-while, for etc
nope
i like this one but
(some #(when (zero? (mod % 7)) %) (iterate inc 20))
just replaces first, filter with some, whenright, some
just makes it more complicated