This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
- # adventofcode (18)
- # announcements (1)
- # babashka (153)
- # beginners (73)
- # bristol-clojurians (4)
- # calva (1)
- # cider (6)
- # clj-kondo (38)
- # clojure (154)
- # clojure-dev (12)
- # clojure-europe (7)
- # clojure-finland (11)
- # clojure-nl (70)
- # clojure-spec (13)
- # clojure-uk (101)
- # clojuredesign-podcast (2)
- # clojurescript (15)
- # core-async (30)
- # cryogen (1)
- # cursive (5)
- # devops (1)
- # duct (4)
- # figwheel-main (1)
- # fulcro (19)
- # jobs (12)
- # kaocha (17)
- # luminus (2)
- # malli (8)
- # music (5)
- # nrepl (13)
- # off-topic (20)
- # overtone (3)
- # re-frame (7)
- # reagent (38)
- # shadow-cljs (13)
- # specter (3)
- # tools-deps (6)
- # vim (7)
Data structure question. What is the idiomatic way in clojure to have a map where I can do binary search over the keys?
@finn.volkel I am pretty sure a sorted-map or sorted-set should do all of those things. Implemented using red-black trees under the hood
IIRC, some combination of
rseq and other sequence operations should do what you want, although it does not keep "pointers" into the ordered sequence of keys, so starting with a key and then finding smaller/larger ones will probably always be O(log N) for the first, then O(1) for each one afterwards as long as you keep going.
@U0CMVHBL2 thanks, I wasn't aware of the
subseq and that it runs in O(log n). So you are saying something like
(first (rsubseq (sorted-map .....) <= x))) in only O(log n) even if the subsequence returned by
rsubseq might be quite large?
It is O(log n) to find the first element, then I believe it is O(1) per element that you actually traverse after that. If you traverse m elements, it cannot be faster than O(log n) + linear in m
Clojure rarely provides core functions that do not have good performance characteristics, in general. Very little of the built-in documentation in doc strings gives big-oh notation running time -- a few will mention constant or logarithmic time, but not many.
A "sequence" in Clojure is some abstract thing that promises to implement first and rest. Many of them are implemented lazily, so do not realize long things unless you traverse them.
@finn.volkel ^^^ not sure if you saw that, so pinging you via @ in case not. Sorry for the bother if you have seen it already.
@U0CMVHBL2 thanks, that cleared it up. I thought that if it's lazy it's mentioned explicitly. So in absence of the mention lazy I always assumed the sequence is evaluated eagerly.
If a function returns a Clojure map, vector, or set, it is fully evaluated before returning -- there are no such lazy objects in Clojure. Sequences are not always returned as lazy, but usually are. Sometimes the docs say so explicitly, but apparently sometimes not.
If you look at the definition of
subseq e.g. by doing
(source subseq) in a REPL session, you will see that the final expressions returned are from
(take-while ...) , and
take-while is documented to return a lazy sequence
it's more of a Cursive question rather than a Clojure question. If I write tests about another clj file, do I need to reload the file in the REPL before running the test?
@dierre_spam In general, yes. Not sure whether Cursive has any automated reload-on-save logic. But it's a really good habit to get used to always evaluating each top-level form you change as you are editing. It's going to be just a hot key to press and after a while it will become second nature. Edit, eval, edit, eval. Then your REPL always reflects the state of your code.
And if you evaluate forms as you edit them, then you don't even need to save the file each time. I often edit, eval, edit, eval, switch to the test file, run tests (another hot key), switch back to source file, edit, eval, ... save.
You'll hear people talk about a REPL-Driven Development workflow but what they really mean is a workflow where your REPL is always up-to-date: you eval every single small change as you make it, so you can always test your code as you work. It's often helpful to have "Rich Comment Forms" in your source code that contain expressions that exercise your functions so you can easily eval those and check your results:
(comment (my-func 123))
The ideal workflow is never typing directly into the REPL -- type into source/test files and evaluate code from there instead. And use
(comment ,,,) forms for "scratch"/test code so you don't accidentally leave code exploration at the top-level of a file.
Hi all. Question: I am trying to map a 1d vector to a 2d vector so that [1 2 3 4] and [   ] produces [[1 5] [2 6] [3 7] [4 8]]. Any suggestions?
(cmd)(user=> (map cons [1 2 3 4] [   ]) ((1 5) (2 6) (3 7) (4 8)) (ins)user=> (map (comp vec cons) [1 2 3 4] [   ]) ; in case vector is mandatory ([1 5] [2 6] [3 7] [4 8])
map takes any number of cols (they become the respective args on each call of the f passed), and cons adds a new element at the front of some other coll to make a list
Is there something similar to Javadoc for Clojure? Main benefit being your editor can give your internal references and info
If you want to produce good documentation for others who use your (open source) code, take a look at http://cljdoc.org which combines your docstrings with additional docs in the GitHub repo -- and also supports Markdown in docstrings and linking to other functions and docs etc.
Also for example cider can jump into definitions of symbols in docstrings at least if you wrap them in backticks
I’m reading about transducers from this site: https://labs.uswitch.com/transducers-from-the-ground-up-the-practice/
And it seems to read like transducers are applied in the “wrong” direction when using
comp. I double checked in the repl, and their output seems correct. Why aren’t they applied right-to-left?
the arities are documented here https://clojure.org/reference/transducers#_creating_transducers
this part of the doc that goes step by step might be clearer https://clojure.org/reference/transducers#_defining_transformations_with_transducers
each one takes the previous transform as an arg, and decides whether to call it on the data it sees
> Composition of the transformer runs right-to-left but builds a transformation stack that runs left-to-right (filtering happens before mapping in this example).
I’m not totally confident about how it fits in my brain, but I’m still reading some of these docs
from the "creating transducers" section:
rf is the "continuation" or "target" - the transducing context, which wraps the previously composed transducers if any
(fn [rf] (fn ( ...) ([result] ...) ([result input] ...)))
the transducer should call rf on its input (unless you are filtering, then you skp calling rf for this data)