Fork me on GitHub

for parsing XML is clojure/data.xml the standard way ? I keep forgetting 🥺


Yes, and use the latest (alpha) release @U3ES97LAC

Tim Abdulla01:09:57

does anyone know why in a lein repl, classpath/classpath returns an empty list, but classpath/system-classpath returns all the things you would expect to see (e.g. deps, my project's own classes, etc.)?


I don't know which library you're referring to with classpath there but I suspect this may be to do with how DynamicClassLoader instances are handled in nREPL...

Tim Abdulla01:09:54

org.clojure/java.classpath is the library

Tim Abdulla01:09:09

I am both a jvm and clojure beginner so a lot of fun things to learn here 😄


If you use the official Clojure CLI, you'll get the results you expect from those two calls.


(but I expect the books/tutorials you're following are using lein?)

☝️ 2
Tim Abdulla02:09:10

ah, you are correct

Tim Abdulla02:09:49

I assume lein has its own way of making class-loading work that confuses that lib


Most likely nREPL that lein uses but, yes, there is a lot of "extra stuff" going on in lein repl compared to clj (the official CLI's way of starting a REPL).

Tim Abdulla02:09:37

gotcha. it (the classpath coming back as empty) was breaking another library that I was trying to use... downgrading to jdk 8 helped.

Tim Abdulla02:09:24

thanks again for the help and information 🙂 unrelated: would you recommend any great open-source clojure codebases to peruse? I find that's helpful to learn the idioms and conventions of a new language


@U02D4EJ97TR There aren't many open source applications -- and libraries tend to be sufficiently specialized that they often do non-idiomatic things. metabase and cljdoc are probably the two biggest open source applications that come to mind that are supposedly fairly idiomatic.


The main advice is to separate pure functions from side effects. You'll hear "functional-core, imperative-shell" as a good way to organize Clojure programs.


I think "idioms in the small" have changed a lot over Clojure's 10+ years since we didn't have core.async, Spec, or transducers in the early days, and those have all led to new idioms for writing programs. nil-punning is still a pretty core idiom.


I'd also suggest watching every Rich Hickey talk you can find but especially Simple Made Easy (there's a new 10 year HD remaster available), Spec-ulation, Language of the System, Maybe Not. Transcripts are here if you prefer reading

Tim Abdulla15:09:43

thank you! how often are transducers used? I got the impression from reading Programming Clojure that they are fairly niche and used mostly in situations in which performance is a concern. it also didn't cover core.async at all -- presumably it was written before that was a thing


@U02D4EJ97TR Which edition of Programming Clojure? Transducers came with Clojure 1.7 which was mid-2015. I think it takes some getting used to, mentally going from ->> pipelines to transduce, but for complex pipelines/transformations you can clearer code and you certainly get faster code. It's taken me a while to make the switch and I think it'll take a while before the transducer-based approach becomes the default way that books and tutorials take -- but I think for folks new to Clojure, using transducers should be considered idiomatic and preferred in many cases over ->>.

Tim Abdulla18:09:38

it's the third edition, published in Feb 2018. I believe that is the most recent edition, too. sometimes it's a bit difficult to see when one ought to use a particular language feature, or how prevalent it actually is. e.g. record datatypes, specs, etc.


Ah, yes, so it was mostly written pretty soon after transducers were introduced I suspect.


For the whole types thing, this flowchart is still pretty good advice:

👍 2

Clojure Applied is a good book for practical development stuff -- although it leans heavily on defrecord which the author (Alex) has said he would tone down in a 2nd Ed and focus more on plain hash maps.

🙌 2
Tim Abdulla19:09:41

thanks! yeah, I think a more practical perspective would be helpful. I have a decent idea of the breadth of features clojure has, but not much insight into how to put them together, basically.


Depending on your background, FP can be quite a big shift (with immutable data and an emphasis on higher-order functions).


(defn foo [{exx :x}] (foo-1 exx))
is there an even shorter way to say this?


(def foo (comp :x foo-1))


(def foo (comp foo-1 :x))?


yea the order is correct in the @U01AKQSDJUX version


(merge {:x [1 2]} {:x [1 10]})
what is a good way to have something like merge but I would like to conj the value vectors? So the result here should be {:x [1 2 10]} or does it show I should not use vectors?


I just found merge-with


I was referring code example , trying to understand how it is built, What is the use of using import-vars here rather than just importing all the method or variable into the namespace


not related to the import-vars, but core idea of compojure-api was to have a multimethod-based macro-expansion system to reduce boilerpate when writing web-apps. Would not use it as any example how to do things, but it… works 🙂


this is the main thing: As a side-note, to know what routes are under a context, the system does a dummy routing request…


main thing in the sense? i did not get it! Do you mean this function is important in compojure-api?


alsoi did not get how the code you shared is related with the import-vars


it’s essential if you want to understand compojure-api itself. the import-vars copies the vars and adds watch to keep the vars in sync between namespaces, copies metadata etc.


I don’t think it’s a good practise nowadays.


The reason I was looking that is. I wanted to wrie good code in clojure and I started to loook into existing code implementations, so got that question


Do you have any suggestion to improve my coding standatds?


I suggest you'll write a post to Clojureverse, I think it's a good place to get help and the message board is persistent, unlike the slack history. Out of the libs I've involved in, reitit and malli are ok'ish.


reitit is a multi-module project, malli has clear separation of features as namespaces. Both have some perf-optimized code which is not pretty thou.


oh, malli actually has cryptic variable names and long lines. Matter of taste.


Sean Cornfield has made a good set of quaöity libs, which are idiomatic.


> The reason I was looking that is. I wanted to wrie good code in clojure in that case, forget import-vars exists

🙌 2
Nikhil Warke09:09:02

My dad wants a simple versioning system UI. He is using folder based system, and he is running out of space and it is getting harder to find changes needed. All existing ones are too bloated for his use case (we've tried git*) so I'm building it for him. I need it fast and cheap. I'm leaning on cljs+electron since I'm familiar with web tech. Any suggestions are welcome. 1. Requirements a. Target OS - Windows 10+ b. Intuitive - the lesser user needs any tech experience the better c. Reliable - worst case scenario is any type of data loss 2. Features a. User will initialize a folder for version control by right clicking on folder and selecting 'Initial VCS' i. The folder will added to VCS with name V1 b. User can view all versions by right clicking on folder and selecting Show all versions i. It will open a new window, where all existing versions are shows as a graph ii. Version Graph Wireframe (attached) c. User can right click a version (V1) and select 'Create new version' to create new copy (V2) d. When User creates a new version i. the system will add a child to graph (create arrow pointing from parent to child) ii. Increment Least Significant Integer by 1 iii. or add suffix .1 to source version's name if starting a new branch e. User can rename version by right click -> Rename f. Double clicking or right click -> Checkout will be update file system with content from the source version. 3. Optional/Good to have Features a. Easy backup for one/multiple/all folders

Jon Boone09:09:40

Great challenge! It seems a few items might be better specified starting with the issues with git that are leading you to implement your own system.

Jon Boone10:09:17

For reference, I began an electron app (in node on the backend) to simply versioning for non-techie users as a class project during my MS program (the class was HCI). There was a quite reasonable node library that already interfaced with git — my effort was choosing the right abstractions to implement in the UI.

Jon Boone10:09:49

So, while not an expert by any means, I have given a similar problem som considerable amount of thought.

Nikhil Warke10:09:50

The main issue is usability. For him learning git is like buying for small backyard.

Nikhil Warke10:09:53

@U025L93BC1M Cool! What sorts of problems did you run into while building? Also, is it open source, it should help reduce the time for 0 -> something by a lot.

Nikhil Warke10:09:25

Git as technology is awesome, it just needs better interface for us humans 🙂


100% sure there are existing solutions that work nicely on windows


How about fossil?


It has a wiki etc., all built into it

Jon Boone11:09:46

Not sure what versioning file systems exist for Windows (last versioning FS I used was in VMS last millennium), but that is a fine solution for individual files.

Jon Boone11:09:13

The key is to determine if you need project versioning or not (essentially git tags serve this purpose for a single repo), and if so, what are the fundamental abstractions and operations you need to support.

Jon Boone11:09:00

Then you can filter potential solutions for appropriate features.

Jon Boone11:09:59

And, I personally always prefer to leverage existing implementations if possible. Hence, my project leveraging electron, git and a node library for git.

Jon Boone11:09:39

@U029PC2K1HV — let me check for the code base. It’s currently not on GitHub (or equivalent), but I think it can be. Just not sure it still works at all, since it was finished back in <tel:2016-06-0|2016-0>6….

Jon Boone11:09:30

I can send you the PDF outlining the goal and trade offs I investigated…

Nikhil Warke12:09:21

@U01EFUL1A8M @dharrigan For UX, I'm starting from the mental model of how User expects his system to work. Unfortunately all tools I encountered so far try to force user to learn their design, which makes them not intuitive and aren't interactive enough to help user learn on the fly (you have to comb through docs to find what you need instead of just being there where it is needed). Also @dharrigan he needs less features than current offerings 😅, so although fossil is nice, it not appropriate. I may use it behind the scenes. @U025L93BC1M Yeah, that is high level plan. For git, I was thinking branches would be better since they fit with his model. As user works (the GUI will automatically - Commit, Commit, Commit) then creating new version (Branch), double click version to Check it out (git checkout branch). Yes! I prefer the same.


I addressed a similar problem (hiding git UI complexity) in my personal knowledge base (PKB) PoC. It's just a few shell scripts that wraps git commands, with a few bells and whistles added: gmx-init, gmx-add, gmx-undo, etc. That's just to say that I agree that 1) git doesn't have the nicest of interfaces to spend brain cycles on, and 2) it's still a good "engine" to power the underlying version control, in stead of reinventing the wheel.

Nikhil Warke13:09:03

> git doesn't have the nicest of interfaces to spend brain cycles on that's going to be used in my future conversations and yes, my thoughts exactly. They solved the 'backend' part so to speak, now it is up to us to make it human friendly ✌️:skin-tone-3:

💯 4

github desktop works for me - i use it for work and if i'm not collaborating its really just a commit and push

Nikhil Warke16:09:05

@U3JH98J4R git != github. I don't need push (for foreseeablegithu future). As for UX, it looks the same as sourctree, git kraken and what have you. Someone (I can't remember who) made a comment that best tools are the ones that do their job so smoothly that User isn't even aware of it (or something similar in spirit). VCS should aim to be that type of tool. After all our job is to create, and not to search how to merge/rebase branches 😄


what about just using butter fs?


kinda overkill but everything happens automatically

Nikhil Warke16:09:03

It seems to be made for Linux. Violates requirement 1.a right off the bat. Also, you have to consider all the other headaches changing the FS would bring, After all we can't let our solution make user consume more time than before, in their workflow


Hi all~ I hope this is the right forum for this. I'm new to Datomic/Datalog and am trying to do the equivalent of a SQL LIKE. I'm attempting to write a query where I'm seeing if a string contains a substring. The query works for an exact match, but when I try to find if there are any strings that start with At first-*

(d/q '[:find (pull ?e [*])
       :where [?e :sentence/text ?text] [(re-find #"At first+" ?text)]]
I get `Execution error at com.cognitect.transit.impl.AbstractEmitter/marshal ( Not supported: class java.util.regex.Pattern` Does Datalog support string queries with regex/wildcards? Is there a way I could do this? Apologies if this isn't the right channel for this!


there is no edn/transit support for regex patterns so I'd guess no. maybe clojure.string/includes? would work better?


@U064X3EF3 Thanks for the answer! Tried and got --

(d/q '[:find (pull ?e [*])
       :where [?e :sentence/text ?text] [(clojure.string/includes? ?text "At first")]]

; Execution error (ExceptionInfo) at datomic.client.api.async/ares (async.clj:58).
; 'datomic/ion-config.edn' is not on the classpath
:face_with_monocle: I guess something is wrong with my general datomic config


@U01EFUL1A8M oooh, I'm using Datomic cloud but maybe the equivalent is (A search for database functions in the Cloud docs didn't turn up anything)

César Olea15:09:01

The error you got about datomic/ion-config.edn is either because you are missing that file in your project, or because you are not including the location as a resource. You should have something like this in your deps.edn file:

:paths ["src" "resources"]
Where src is a directory containing your source files, and resources is a directory containing resource files, it should look something like this:
├── deps.edn
├── resources
│   ├── datomic
│   │   └── ion-config.edn
│   └── schema.edn
├── src
│   └── source_files
Note how ion-config.edn is in a subdirectory inside resources.


Team, I am basically java and big data programmer and in my current organisation I started learning clojure and writing code in clojure. I am able to complete my task in clojure and I am liking the clojure because of its elegant structure and many other benefit, I would like to write better code in clojure, I started with looking into compojure-api code , But I am not getting how I can improve on Clojure as of now I had gone through all basic video tutorial . Rick hickey talk Can any suggest me how I can better my coding skill in clojure , ?


The book Elements of Clojure was suggested to me fairly early on, and it really helped me understand some of the zen of Clojure a bit better.


Do you have soft copy of it? Can you share me please


It's not cool to ask people to send you a pirated ebook. You can buy it here:


was not finding in my country, So asked


Hi everyone, I am getting confused between routing in the web framework like pedestal or ring and routing in reagent application... Can someone more knowledgeable please explain to me the difference...? Maybe also what is running where... which part in server, and which part on the client side...? I am very confused with how to manage routing on both side... Many thanks in advance!!


I'm interested by a simple explanation as well, pedestal is confusing.


@U02DEQJ409F right? 😄 Especially the hash-map of hash-map of hash-map of hash-map to specify routing...


What is your experience with web development?


very little... newbie


Okay. So, the answer to your question isn’t Clojure related. Are you familiar with SPA v. Server Side App?


I thought I did... but then I stumbled upon routing in reagent... and reagent with routing somehow in my head is not an SPA anymore... so where does it run... ? How can you manage different "routed" SPAs from different pages from your server? Also the basics... what is running where...? I have not a clue!


Are you familiar with React?


reagent only ... I am afraid... I thought I can skip JS completely by using just clojure/script... I have a feeling that idea was too good to be true... 😄 I know C/python quite well tho... and I did dabble into JS long time back... when there weren't libraries for everything...


Often you don’t need to know JS, but you will need to understand some basic ideas. Okay. So, to take a step back. Reagent is just a wrapper around React. React is often used to build SPAs. In web land, you have two common ways of building any web app: 1. server side rendered 2. single page app If you do 1, all your routing is handled by your web server (pedestal in your case). So, you would have /index /about /other-page-name If you do 2, you usually have 1 route in your web server (pedestal again) called /index and all the other routes are handled in the front end (browser, client)


So, depending on what you are building, you don’t always need to handle routing in both the front/backend.


The reason you have 1 route on the web server if you go SPA is because with a SPA all your HTML is generated on the front end using JS. If you do server side rendered, all your HTML is rendered on the server using whichever server side language you are using.


Does that make sense for a high level overview?


So routed reagent application will still run on the client... right? whereas if I explicitely want to create routes in my pedestal, then all the processing for generating the pages and hosting the resources is on the server side... right?


> if I explicitely want to create routes in my pedestal, then all the processing for generating the pages and hosting the resources is on the server side... right? Correct. Generating the HTML fo each page is server side. Hosting the resources, like HTML, CSS, JS though, that has to be done on server side no matter what. Just a clarification


> routed reagent application will still run on the client If you use reagent to build a SPA, yes. But, you don’t need to build a spa just because you use Reagent


OK ... does that also mean that if I have routing in my reagent... it is not technically an SPA?


You mean if you have some routing through Reagent? Like, 5 pages are server side rendered and the 3 are done on the front end? I would say that’s a bit of a hybrid. A single page application is just 1 HTML file with some JS that makes the app behave like it’s a traditional server side app. I guess that may be a way to help think about it.


Hi awesome people, How can I disable ssl verification when posting data to an endpoint. I'm using clj-http.client. Any help will be most appreciated,


;; Need to contact a server with an untrusted SSL cert?
(client/get "" {:insecure? true})


You're most welcome 🙂


i have required clojure.test and then required another namespace that defines defmethod impls for the clojure.test/report multimethod. i’d like to “undo” those new impls and have the original clojure.test impls again. is that possible?

Russell Mull16:09:34

defmethod calls MultiFn/addMethod internally: afaict, it's destructive, so you may be out of luck.

👍 2

good find! thank you

Russell Mull16:09:50

Note however that clojure.test/report is a dynamic var, so depending on your situation, you may be able to use binding to provide a different implementation is a specific context.

Russell Mull16:09:05

You could do both together, if you like: (defmulti my-report ...) and then later (binding [clojure.test/report my-report] ...)


ah interesting, yeah


thank you, that’s a cool idea


You can remove any methods that have been added with code like

(defmulti thing :thing)
  (defmethod thing :x [x] x)

  (methods thing) ;; => {:x #function[scratch/eval26535/fn--26536]}
  (remove-method thing :x)
  (methods thing) ;; => {}
if that's useful information ...


simple solution is to copy-paste them into my test_helper.clj file, but that’s messy

George Silva19:09:05

Hello friends. I'm learning from and I'm doing the Armstrong numbers puzzle, where you have to find numbers that the sum of it's digits ^ count of digits of the number == number. Example: 153 = 1**3 + 5**3 + 3**3 => 153 Here's what I have accomplished:

(ns armstrong-numbers)

(defn calculate-number [digit-count digit]
  (Math/pow (Integer/parseInt digit) digit-count))

(defn armstrong? [num] ;; <- arglist goes here
  (let [exp (count (str num))
        calc (partial calculate-number exp)]
    (== num (reduce + (map #(calc (str %)) (seq (str num)))))))
Is there any idiomatic or more idiomatic way of writing this?

George Silva19:09:40

This still fails for 21897142587612075 :thinking_face:


Your code looks efficient and idiomatic to me, with one trivial exception: strings are automatically treated as a seq of characters by operations like map and reduce, so you can write just (str num) where you have (seq (str num)).


Is 21897142587612075 supposed to be an armstrong number? When I run your code, I get

(armstrong? 21897142587612075)
=> true

George Silva19:09:05

yes. weird, why does my test fails? 🙂


Maybe you have stale code in your REPL somewhere? I’d try restarting.

George Silva19:09:49

Yea, let's give that a go. I'm using calva:

clj꞉armstrong-numbers꞉>  (armstrong? 21897142587612075)

George Silva19:09:53

Nope, still fails. Also fails on


Oh that’s interesting, hmm.


(ins)user=> (Integer/parseInt "21897142587612075")
Execution error (NumberFormatException) at java.lang.NumberFormatException/forInputString (
For input string: "21897142587612075"
(ins)user=> (Long/parseLong "21897142587612075")
may be related


in general Integer is only needed for interop with libraries written in java, clojure uses longs

(ins)user=> (type 1)


He’s only calling parseInt on the individual digits, but maybe it’s an overflow issue when you apply Math/pow for large values of digit-count?


Math/pow uses floating point math


Try this

(defn calculate-number [digit-count digit]
  (Math/pow (Long/parseLong digit) digit-count))

George Silva19:09:09

Maybe. Let me try to replace parse long


so the issue might be in floating point precision


Might be. I’ll be curious to see if it makes a difference whether the first arg to pow is an int or a long.


it always converts to double


That’s what I’d expect. But then again I’d expect the code to run the same on his machine as it does on mine.

George Silva19:09:50

No difference. Still false


Interesting. What version of Java?


> it always converts to double that could be wrong - it might convert to float, explicitly converting with double might help

George Silva20:09:02

Changing the code to print the result I get:

(armstrong? 21897142587612075)
Which is a bit different from the original number

George Silva20:09:22

(format "%f" (armstrong? 21897142587612075))


yeah, it's float vs. double precision I bet

👍 2

I bet you’re right.


(ins)user=> (== 21897142587612075 (double 21897142587612075))
(ins)user=> (== 21897142587612075 (float 21897142587612075))

George Silva20:09:01

[email protected]:~$ java -version
openjdk version "13.0.7" 2021-04-20
OpenJDK Runtime Environment (build 13.0.7+5-Ubuntu-0ubuntu120.04)
OpenJDK 64-Bit Server VM (build 13.0.7+5-Ubuntu-0ubuntu120.04, mixed mode)
[email protected]:~$ clj --version
Clojure CLI version


regardless of jdk version, explicit double casting in the right places should fix it

👍 4

but I find it odd that jdk versions could change float / double as Math defaults...


I’m in a REPL running an older codebase, I’m on java 8 still.

George Silva20:09:10

Still no dice lol

(ns armstrong-numbers)

(defn calculate-number [digit-count digit]
  (Math/pow (Long/parseLong digit) digit-count))

(defn armstrong? [num] ;; <- arglist goes here
  (let [exp (count (str num))
        calc (partial calculate-number exp)]
    (== num (double (reduce + (map #(calc (str %))  (str num)))))))

George Silva20:09:33

let me see if this version passes on exercism.orgh

👎 2
George Silva20:09:39

Even with double conversion for both arguments on == still fails


converting to double after reducing doesn't preserve information


you would need to do the double conversion on Math/pow

George Silva20:09:27

👍 yea, that makes sense


on my jvm Math/pow always converts to double though

George Silva20:09:19

Still no luck. Fails on my machine & on exercism

George Silva20:09:06

On python this worked on the first try (I was double checking the result on exercism)

>>> a = 21897142587612075
>>> result = 0
>>> for x in str(a):
...     result = result + (int(x) ** len(str(a)))
>>> a == result


you don't need fractional exponentiation, and this fixes it for me:

(defn calculate-number [digit-count digit]
  (apply * (repeat digit-count (Long/parseLong digit))))


if you remember your middle school math you can verify that's exponentiation :D

👍 2

there are also libs for doing math on types other than double, they just don't come with the vm


that could be reduce * to match your sum elsewhere, it's equivalent


using long to convert the result of Math/pow would likely work too


the loss of info is in the series of floating point additions for the digits


the result can be held in a double, but double clearly isn't big enough to do the full chain correctly

George Silva20:09:41

haha @U051SS2EU thanks. Indeed I do remember exponentiation. Interesting nevertheless!


@U020U1YDMMK also you've kind of hit a weak spot in clojure, there are libraries for numerics but it tends to be clumsy to write and poor in performing for numeric code in my experience

George Silva20:09:14

Thanks , to you both!

(armstrong? 21897142587612075)

George Silva20:09:48

@U051SS2EU I mean, this comes as surprise, as there is a lot of movement on clojure becoming a strong data-science language.


it's great for the kind of data manipulation that uses set theory, not the kind that uses number theory IMHO

👍 2
George Silva20:09:46

It's not my line of work, but since I'm learning I was kinda puzzled 🙂 My focus at the moment is more about learning how to think functional lambdalove


to expand on the above: a huge advantage with clojure is you can move the kind of set manipulation logic that is usually pushed into the db side, and is a better general purpose language than any db DSL


and most "big data" / "data-science" stuff is more about those relational operations (as I understand it), as opposed to AI and physics simulation where you need strong numeric perf

George Silva20:09:47

There is a lot of data manipulation, for sure. I don't do a lot of ds, so I'm fine with it. I think my main interest with clojure comes from expanding from the oop paradigm and it is an elegant language. After a while the parenthesis disappear indeed 🙂 I'm mostly interested in building web servers with it.


that's probably the most common usage of clojure in the wild, closely competing with back end services


(of course many deployments are both)

George Silva20:09:35

Yeap! Let me rephrase that - I'm interested in backend services. Webservers I plan to use what we have in the wild 🙂

Franco Gasperino21:09:48

Good afternoon. I'm looking for a more idiomatic way to perform the following:

(defn rebuild 
    "Takes a vector of keys (ks) and a value (v), returning
     a nested map of key traversals -> value."
    [[ks v]]
    (loop [m {} k (peek ks) s (pop ks) p []]
      (if-not (seq s)
        (assoc-in m (conj p k) v)
        (let [p (conj p (first s))]
          (recur (assoc-in m p {}) k (rest s) p)))))
=> (map rebuild [[[:a] 1] [[:b :bb] [2 3]]])
({:a 1} {:b {:bb [2 3]}})
To pull this off, it appears the ability to look past the current iteration to finalize is something that would be tricky with a reduce-like approach.


like, don't? instead of writing could to transform whatever structure from whatever format to nested maps, write code to take whatever format and turn into arguments you can pass right to assoc-in


in the example of above, those paths are able to be passed directly to assoc-in, so it isn't a good illustration of rebuild


so for example

user=> (map (partial apply assoc-in {})  [[[:a] 1] [[:b :bb] [2 3]]])
({:a 1} {:b {:bb [2 3]}})
user=> (reduce (partial apply assoc-in) {} [[[:a] 1] [[:b :bb] [2 3]]])
{:a 1, :b {:bb [2 3]}}

Franco Gasperino21:09:39

sheesh, staring me right in the face


(using partial and apply like that isn't really idiomatic, but it is brief)


> using partial and apply like that isn't really idiomatic How come?


in general using the #() anonymous function form is considered more readable, and using the #() usually will make debugging easier


Oh, so you were referring more to partial, then?


I thought there might be something about the combination of partial and apply that I'm unaware of.


if you use partial and there is an exception you'll get an additional stack frame like [clojure.core$partial$fn__5858 invoke "core.clj" 2628] which can be confusing


right, more just partial (and similarly with comp)


Thanks for the clarification 👍


Anyone have any insight/articles for how to tell when your data naturally fits maps over vectors or vice-versa?

Russell Mull22:09:51

That's quite an interesting question. There are a few different angles you can think of it from. One is in terms of inherent structure. Is this think "intrinsically" associative? Use a map. Is it "intrinsically" sequential? Use a vector. That's maybe the least helpful. Another is in terms of function semantics. Can you view this data as a function from an (natural number) index to a value? That's a vector. From some other key to a value? That's a map. Another could be by access pattern. Some collection of information could have a pretty natural representation as either a map or a vector, with different shapes. But you could choose one or the other based on how you want to look things up. Is this at all helpful?


Thanks @U7ZL911B3. At the moment I think I’ve chosen the data structures because of an access pattern - namely I want to be able to retrieve something easily. The question stems from a project I’m working on. Basically, I have a bunch of text inputs whose value are controlled by some state (think React controlled component). When an input changes, I want to be able to update the matching piece of state. Using a map I can retrieve the state by :id, but it makes describing the UI trickier than with vectors.

Russell Mull00:09:56

If using vectors would turn the update into a "scan until you find the right thing" algorithm, that's a pretty clear indication that the data is supposed to be in a map.


Yeah you’re right


But it’s all complicated by a module that requires it’s data in vector form


So then I need to parse/transform the map into a vector


It seems like I’ve modelled the data wrong


So with the vector approach, it becomes easy to express the UI via a map and it also becomes easy to send the data to the other module but now it’s not as fluent to update the state. Like you said, I’d have to scan to find the Id


It just struck me that perhaps funnelling all the input change events through a common handler is not the best approach. Perhaps I’d be better off creating a function for each input that “knows” what piece of state it’s updating…


Sorry, just brain dumping now. Thanks for your input :thumbsup:


You can use a vector of maps

[ {:key val} 
  {:key val}
  {:key val} ]
And have a react component that renders one or more text boxen corresponding to the maps in the vector. Of course, if you want to update them, it kinda sucks. So you might have each map indexed by its own unique ID, making a "map of maps."
(def over-map
{1 {:hax 'bax'}
 2 {:hax 'trax'}
 3 {:hax 'snax'}
 4 {:hax 'attax'} }
The "keys" to each submap can be simple integers, for example, and you can get them out of the over-map by using that index. (get over-map 1) -> {:hax 'bax'} (get over-map 4) -> {:hax 'attax'} When you want to render components you can grab all the vals of over-map one by one... you can "iterate" over the over-map index. It might save you some thoughtwork depending on your use-case.


Thanks @U3ES97LAC, this is essentially what I’ve done for now. Incidentally, this is tricker in JS because the methods on Map yield iterators which can’t be used in an expression context


Unless you did something like this I guess

[...m.keys()].map(k => m.get(k))


Uh, you're using vanilla JS ?


Both, going from one to another


as in, rewrite


Sorry, I thought I’d just mention that JS part as I found it interesting the “friction” in the JS APIs when you’re used to Clojure


Ah I see. Which React library for ClojureScript are you using if I may ask?


Just Reagent