beginners

Getting started with Clojure/ClojureScript? Welcome! Also try: https://ask.clojure.org. Check out resources at https://gist.github.com/yogthos/be323be0361c589570a6da4ccc85f58f.
Jacob Rosenzweig 2021-05-24T04:04:59.299100Z

Lol I love how destructuring on the sequential order instead of the names takes care of a suite of problems I regularly see in JS.

solf 2021-05-24T04:09:33.299200Z

Clojure does both array and map destructuring, if that’s what you’re referring to:

(defn foo [{:keys [foo]}]
  foo)

(foo {:foo 42})

(defn bar [[_ bar]]
  bar)

(bar [10 40])

2😄
flowthing 2021-05-24T05:24:41.299600Z

> Does what I was looking for. There’s little documentation on the cap function. What does it do? cat is a transducer (https://clojure.org/reference/transducers). I like to think of it as just the cat part of mapcat or concat. > Actually I should have used (apply concat coll), works as well Yeah, there are many ways to skin this cat (pun intended, I guess): https://web.archive.org/web/20190925191622/http://chouser.n01se.net/apply-concat/ apply concat works, but doesn't return a vector. You can vec it, of course, but then there's little reason to use it over into [] cat. If you don't actually need a vector, then you can also do either (sequence cat [[[1 2 3]] [[12 13 14] [10 50 60]]]) to get a lazy seq or (eduction cat [[[1 2 3]] [[12 13 14] [10 50 60]]]) to get an eduction, depending on what you need. Transducers are nice in that they are performant and they compose well. But yes, apply concat is another option, as is mapcat identity, or mapcat seq, etc.

1❤️
valerauko 2021-05-24T06:25:10.300300Z

is there a way to make leiningen automatically update pom.xml whenever there are changes to the project dependencies?

dharrigan 2021-05-24T06:40:54.300700Z

Consider this? <https://github.com/liquidz/antq> this will update your pom.xml and your project.clj too 🙂

valerauko 2021-05-24T06:47:35.301300Z

that's in a bit different direction... i'm using lein-ancient currently for that purpose and it's alright

valerauko 2021-05-24T06:47:53.301800Z

my issue is that when somebody on the team changes/adds dependencies in project.clj they have to manually do a lein pom afterwards

valerauko 2021-05-24T06:47:59.302100Z

which is prone to be forgotten

valerauko 2021-05-24T06:48:34.302600Z

thus i'd want to automate updating pom.xml but i have no idea how

dharrigan 2021-05-24T07:27:03.303100Z

antq can update the pom directly, by excluding others

dharrigan 2021-05-24T07:27:16.303300Z

<https://github.com/liquidz/antq#--skipproject_type>

dharrigan 2021-05-24T07:28:05.304100Z

also, if you were to use antq, for example, then it would update the project.clj and the pom.xml too

dharrigan 2021-05-24T07:29:40.305200Z

alternatively, you could have a git commit hook (assuming you are using git) that would invoke the update to the pom (via lein or antq) before committing.

valerauko 2021-05-24T12:11:26.305900Z

thanks, i'll give it a try

valerauko 2021-05-24T12:12:09.306700Z

but as i said, the issue isn't really about keeping dependencies up to date, it's about keeping pom.xml and project.clj in sync without any manual intervention

dharrigan 2021-05-24T12:13:47.306900Z

:thumbsup: 🙂

lassemaatta 2021-05-24T12:49:43.307800Z

Perhaps a git hook might help?

valerauko 2021-05-24T13:01:51.308300Z

that has occurred to me, but i find git hooks really difficult to share across the team.

valerauko 2021-05-24T13:02:13.308900Z

do you know a way that could be overcome? (eg i can't check .git/hooks/pre-push in)

lassemaatta 2021-05-24T13:15:41.311500Z

Based on a quick browse through google, I believe git > 2.9 supports defining the location of the hooks -> you can create a directory for them and commit them. I haven’t tried this, but it might be what you’re looking for.

valerauko 2021-05-24T13:17:11.312500Z

i think i've seen that too, but i couldn't get a repo-local config of that working

Endre Bakken Stovner 2021-05-24T13:35:46.315400Z

How would you write the Python example at the bottom idiomatically in Clojure? I guess you could use

(apply merge-with &lt;some-custom-func&gt; (into {} [[1, 2], [1, 4], [2, 5], [2, 4]])) 
But can I get away with using a built-in function?
from collections import defaultdict
l = [[1, 2], [1, 4], [2, 5], [2, 4]]
d = defaultdict(list)
for (parent, child) in l:
    d[parent].append(child)
print(dict(d.items()))
# {1: [2, 4], 2: [5, 4]}

ghadi 2021-05-24T13:37:28.315800Z

(doc group-by)

Endre Bakken Stovner 2021-05-24T13:38:17.316200Z

Derp. It is a function I know inside out 😳 So the solution is group-by then merge-with.

Endre Bakken Stovner 2021-05-24T13:48:04.317500Z

I am sure someone can do it moar purdy:

(def l [{:a 1 :b 2} {:a 1 :b 3} {:a 4 :b 5}])
(def g (group-by :a l))
(zipmap (keys g) (for [l (vals g)] (flatten (for [{:keys [a b]} l] [b]))))
;; {1 (2 3), 4 (5)}

NoahTheDuke 2021-05-24T13:49:07.317700Z

user=&gt; (def l [[1, 2], [1, 4], [2, 5], [2, 4]])
user=&gt; (reduce (fn [m [k vs]] (assoc m k (mapcat next vs))) {} (group-by first l))
{1 (2 4), 2 (5 4)}

1🙏
NoahTheDuke 2021-05-24T13:51:30.318400Z

or (reduce (fn [m [k vs]] (update m k conj vs)) {} l), don’t even need the group-by

1🙏
Endre Bakken Stovner 2021-05-25T15:31:32.378200Z

I love this answer. The fact that I can conj to nil Haskell-style and get a list is going to make much of my code cleaner.

1😊
Joni Hiltunen 2021-05-24T15:45:41.320300Z

Sorry if this is the wrong channel... Garden/Spade specific. I'm trying to get started with the re-frame template and I included garden+spade but I can't figure out how I would set a hoverattribute for my links 😄 any tips? https://gist.github.com/Sose/79e79d9b37efdbfe50cb202d94c3e3c7 or if anyone knows any example projects online that use garden+spade so I could dig around their code

Joni Hiltunen 2021-05-24T15:51:47.321100Z

okay, I figured it out with help from https://libraries.io/clojars/hendekagon%2Fgarden ... it's [:&amp;:hover {:color :blue}]

2021-05-24T16:19:10.321300Z

With a modern OS, if you use the right IO API (the one java nio uses), time isn't wasted on threads waiting on IO - the IO call suspends the thread and the completion of the IO is the kernel's signal to wake the thread. the hard part from a developer point of view is managing the inter thread coordination (clojure's immutability helps make that a lot simpler, core.async can help too if used correctly)

2021-05-24T16:21:11.321500Z

the book Java Concurrency In Practice can help a lot if you are planning on micro-optimizing concurrent code https://jcip.net/ - it's a really counter intuitive domain and unless you are already experienced with concurrency, the optimizations you end up needing are likely not to look like the ones you are imagining right now.

2021-05-24T16:22:31.321800Z

for truly high throughput situations the dominating concerns end up being things like cache usage and playing nicely with speculative execution

2021-05-24T16:25:18.322Z

just a small thing - take is redundant on repeatedly - you can replace (take n (repeatedly f)) with (repeatedly n f)

2021-05-24T16:28:09.322200Z

with those changes:

(defn random-string-list
  [list-length string-length]
  (repeatedly list-length
              (fn []
                (apply str (repeatedly string-length
                                       #(rand-nth letters))))))

2021-05-24T16:36:05.322800Z

my hunch (or vague recollection of the actual explanation) is that things that act like entities coming as first arg works with message passing / OO conventions from smalltalk (as later adapted by java, c++ and friends) (message thing arg) and things that act like collections coming last (action parameter things) works with data processing idioms coming from lisp (map, filter, etc. etc.) - for me personally the flip in order helps me categorize them as they are different idioms of programming

1
2021-05-24T16:38:59.323Z

as the RH quote above describes, both idioms existed in common lisp with the introduction of CLOS (the OO system for common lisp), and clojure just follows along

1
2021-05-24T16:39:43.323200Z

fun trivia, many don't realize that common lisp was one of the first few languages with a full featured object system

2021-05-24T16:41:45.323400Z

a note: there's no such thing as a "clojure regex" - on the jvm clojure uses java regex, in cljs clojure uses javascript regex - this is the best cross platform regex guide I've found and I return to it often: http://www.regular-expressions.info/ - it has great comparison of the featureset / syntax of various regex systems (from grep, ed, sed, java, perl, c ...)

2021-05-24T16:42:36.323700Z

bad site design / UI, but top quality info that's well organized once you figure out how it's meant to be navigated

2021-05-24T16:46:29.324300Z

As a beginner, Instarepl looks really helpful and I would love it if there were a new maintainer https://github.com/LightTable/ClojureInstarepl

2021-05-24T16:58:11.324500Z

> doesn't work for deeply nested elements, 2 levels is the max if you actually need this, tree-seq is probably the easy way to do it

(-&gt;&gt; [[1 2 3] [[4 5 6]] [[[7 8 9]]]]
     (tree-seq coll? identity)
     (filter #(and (vector? %)
                   (number? (first %)))))
([1 2 3] [4 5 6] [7 8 9])

2021-05-24T16:58:47.324700Z

of course you can throw vec on the end if the result needs to be a vector

Ivan Koz 2021-05-24T16:58:57.324900Z

isn't that what i did above?

2021-05-24T16:59:42.325200Z

my apologies - my eyes blur and I lose cognitive function when I see "flatten" in code

Ivan Koz 2021-05-24T17:00:17.325500Z

no worries, yours is much cleaner

2021-05-24T17:01:10.325800Z

oh I see now, you put the filtering logic inside the tree-seq child predicate

2021-05-24T17:01:25.326Z

kind of

Ivan Koz 2021-05-24T17:01:55.326200Z

yes, i prefer your way, shows that i lack experience =)

seancorfield 2021-05-24T17:24:29.326400Z

I think you can get this functionality in a few other editors — but automatic evaluation is normally disabled because it can be fairly awkward to use (it will often trigger while you’re editing code and evaluate an “incomplete” expression which could well do something unexpected or unwanted) and it only saves you one key chord in most editors anyway since eval form / eval top-level form is usually just a hot key operation.

seancorfield 2021-05-24T17:24:44.326600Z

What editor are you using @rob370?

indy 2021-05-24T17:26:47.327700Z

@noisesmith mind enlightening why flatten is that bad? :)

2021-05-24T17:29:14.328100Z

In clojure it's an antipattern because it's so common to use vanilla sequential structures to hold data, and a flatten (as in clojure.core/flatten) call in your processing eliminates this structure.

2021-05-24T17:29:51.328300Z

(unless the sequential data is inside a hash-map or whatever to dead-end the recursive flatten)

2021-05-24T17:30:17.328500Z

flatten is extremely slow and tends to encourage / facilitate poor design

indy 2021-05-24T17:32:30.329700Z

Got it, time to play with tree-seq and clojure.walk

jaihindhreddy 2021-05-24T17:59:42.330800Z

Does the Java standard library contain an impl of top-k (C++ calls it std::partial_sort)? Edit: Looking for a more efficient equivalent of #(take %2 (sort %1))

dpsutton 2021-05-24T18:01:03.331400Z

I solved this problem with a bounded size heap: <https://github.com/dpsutton/heap-keep/>

1💯
jaihindhreddy 2021-05-24T18:02:36.332200Z

As a transduction no less. Thanks! Was wondering if the Java std lib had it, because it's a (relatively) common operation.

jaihindhreddy 2021-05-24T18:04:04.332800Z

That being said, the Priority Queue does much of the heavy-lifting, so that's good to have.

dpsutton 2021-05-24T18:05:13.333800Z

yeah. and you can take the idea. i think the priority queue can give you an unordered array or collection of items or you can drain the heap and have sorted results. it's essentially bounded heap sort in that way

1✔️
jaihindhreddy 2021-05-24T18:07:58.334Z

Seems like this would fit right-in, in xforms: https://github.com/cgrand/xforms

2021-05-24T18:35:05.334300Z

I’m using IntelliJ with Cursive, but I guess the thing that seems really valuable to me is more just seeing the flow of data through the program moreso than evaluating with a keypress vs. not https://www.youtube.com/watch?v=H58-n7uldoU

seancorfield 2021-05-24T18:53:27.334600Z

I don’t think that feature ever made it into a released version of LT — by the time it got out into the wild, it was pretty much a “regular editor” and a lot of the cool features shown off in the early videos had been dropped 😐

Juλian (he/him) 2021-05-24T19:26:28.335600Z

is it okay to use unicode characters for variable/function names? like, using xᵢ and xᵢ₊₁ ?

Ivan Koz 2021-05-24T19:35:34.336200Z

@julian608 As wise people say. Always code as if the guy who ends up maintaining your code will be a violent psychopath who knows where you live.

4➕1😆
pavlosmelissinos 2021-05-24T19:36:11.336500Z

Why would you want to do that though?

Juλian (he/him) 2021-05-24T19:38:59.336700Z

I think it would be useful for implementing mathematical formulas

Ivan Koz 2021-05-24T19:43:03.336900Z

I don't even know how to write subscript characters, imagine what people gonna feel using or modifying your code.

Juλian (he/him) 2021-05-24T19:43:40.337100Z

that's a valid point

Ivan Koz 2021-05-24T19:44:07.337300Z

for example, in your in-lined variable above i could barely read the subscript characters, they are so small

Ivan Koz 2021-05-24T19:44:31.337500Z

Juλian (he/him) 2021-05-24T19:45:51.337800Z

they mess up the monospace font in my editor, too... I think I'll avoid using them. but what about greek letters for angles?

Ivan Koz 2021-05-24T19:46:21.338Z

same thing, nobody wants to write code copy pasting from a character table

Ivan Koz 2021-05-24T19:46:38.338200Z

we don't have greek keyboards

pavlosmelissinos 2021-05-24T19:47:37.338400Z

Well, some of us do 😛 Personally speaking, I wouldn't feel too comfortable working on a project that used unicode like that. Ligatures might be an ok compromise, if your editor supports them. That way, you could type out ascii but you'd end up seeing unicode.

1
Ivan Koz 2021-05-24T19:51:59.339100Z

look at how https://github.com/sicmutils/sicmutils is rendering to latex, maybe useful to you

dabrazhe 2021-05-24T21:27:11.340700Z

Thank you all, great help and discussion

BuddhiLW 2021-05-24T21:49:48.346800Z

1. What do I do, when I have a n-arrity function and I want to apply partially first other argument than the first? 2. How to pass an argument as the regex, into (str/split <string> <regex>)? I would like to wirte something like this, in which I face (2.)

(defn split-reg [filename reg]
  (-&gt;
   (str/split filename #reg)
   (second)))
Then, I want to apply this function in the following manner, in which I think of (1.):
(map #(split-reg % "my-regex") &lt;coll&gt;)

2021-05-24T21:55:11.347Z

I don't believe you can pass the literal syntax. e.g #"..." directly as an argument. There are a couple libraries that seem to get around this limitation, but i wouldn't jump to them if you only have a couple cases. ^ wrong see sean corfields response below

2021-05-24T21:58:17.347300Z

Some useful termonology: https://clojure.org/reference/reader#_dispatch The dispatch macro causes the reader to use a reader macro from another table, indexed by the character following The dispatch character is # and the next character in this case is " so it knows it's a regex.

2021-05-24T21:59:58.347500Z

regel is a library that would allow for the functionality you want https://github.com/lambdaisland/regal

seancorfield 2021-05-24T22:01:31.347800Z

You could either pass the literal regex in as #"my-regex" or you could call re-pattern on a string to turn it into a regex: (re-pattern "my-regex") (although there are some caveats about special characters).

seancorfield 2021-05-24T22:02:20.348Z

So your call would be (map #(split-reg % #"my-regex") &lt;coll&gt;) in the first case — which would be the preferred way to do things.

BuddhiLW 2021-05-24T22:06:06.348200Z

My patterns are all numbers and/or letters, generally upper-case. But, I wish to apply it to a lot of different patterns. That would nicely work with re-pattern, I suppose?

seancorfield 2021-05-24T22:08:56.349400Z

Yes, if the pattern is a variable string coming from some other code, that would be the better approach.

(defn split-reg [filename reg]
  (second (str/split filename (re-pattern reg))))

(map #(split-reg % some-string) some-coll)

seancorfield 2021-05-24T22:09:36.349600Z

dev=&gt; (clojure.string/split "This is a string!" (re-pattern " "))
["This" "is" "a" "string!"]

BuddhiLW 2021-05-24T22:10:03.349800Z

That did work great!

(defn split-reg [filename reg]
  (-&gt;
   (str/split filename (re-pattern reg))
   (second)))

#'user/split-reg
$ ls |&gt; (map #(split-reg % "teste"))
("1.txt" "2.txt" "3.txt")
Thank you!

1
2021-05-24T22:20:37.351Z

Is their a way I can do this:

(defn format-element [element]
  (cond-&gt;&gt; (re-matches #"^:\w+$" element)
           (to-register)
           
           (re-matches #"^(:\w+)\[(\d+|\w+)?\]" element)
           (to-reg-array)))
I tried (some-&gt;&gt; as well. I want to take a string and do a regex on it, then depending on what re-matches it matches against, pass the resulting matches to a function to format it.

2021-05-24T22:21:07.351500Z

What I'm trying to avoid is having to do the regex match twice, once to match to know if the string matches then again to get access to the actual matches

2021-05-24T22:34:39.353Z

I have this, but feels clunky

(def matchers-and-formatters {#"^:\w+$" to-register
                              #"^(:\w+)\[(\d+|\w+)?\]" to-reg-array})
(defn format-element [element]
  (loop [matchers (keys matchers-and-formatters)
         formatters (vals matchers-and-formatters)]
    (if (seq matchers)
      (let [res (first (re-matches (first matchers) element))]
        (if res
          ((first formatters) res)
          (recur (rest matchers) (rest formatters))))
      element)))

walterl 2021-05-24T22:37:48.353100Z

(defn format-element [el]
  (some (fn [[rx fmt]]
          (when-let [match (first (re-matches rx el))]
            (fmt match)))
        matchers-and-formatters))
(untested)

2021-05-24T22:40:41.353300Z

That seems to work and is nice! I wasn't aware of when-let, I'll need to go read and understand this. Thank you!

1👍
ghadi 2021-05-24T22:43:45.353900Z

if you care about the captures, don't throw them away by calling first

ghadi 2021-05-24T22:44:55.354100Z

i.e. pass the whole result of re-matches to the formatter

(defn format-element [el]
  (some (fn [[rx fmt]] (some-&gt; (re-matches rx el) fmt))
        matchers-and-formatters))

1👍1❤️
ghadi 2021-05-24T22:45:06.354300Z

and let the formatter destructure

2021-05-24T22:48:14.354800Z

Man, i have so much to learn. That's so concise

2021-05-24T22:59:41.355Z

Thanks for the help guys, i have stuff to look up (Y)