Fork me on GitHub
#beginners
<
2023-01-23
>
popeye09:01:22

Can any one try below code in repl

(defn -occurance [str]
  (let [split    (clojure.string/split str #"")
        str-atom (atom (first split))
        cnt      (atom 1)]
    (reduce (fn [acc v]
              (reset! str-atom v)
              (add-watch str-atom :watcher
                         (fn [_ _ prev curr]
                           (println "  prev " prev)
                           (println " curr " curr)
                           (if (= prev curr)
                             (swap! cnt inc))
                           (do 
                             (println "--1 --" @cnt " " cnt)
                             (println "-- " (str @cnt))
                             (conj acc (str @cnt prev))
                             (reset! cnt 0)
                             acc))))
            []
            split)))

(-occurance "AABBCCCAA")

I am not getting y the error is ; Execution error (ClassCastException) at clojure-noob.macro/-occurance$fn$fn (form-init1532263062898764511.clj:151).
; class java.lang.String cannot be cast to class clojure.lang.IFn (java.lang.String is in module java.base of loader 'bootstrap'; clojure.lang.IFn is in unnamed module of loader 'app')

rolt09:01:57

you're shadowing str

popeye09:01:54

clj꞉clojure-noob.macro꞉> 
(def p (atom 1))
#'clojure-noob.macro/p
clj꞉clojure-noob.macro꞉> 
(str @p)
"1"
clj꞉clojure-noob.macro꞉> 

popeye09:01:07

This would work right? whats wrong ?

Martin Půda10:01:48

When you call (-occurance "AABBCCCAA"), str has value "AABBCCCAA". But then you call `

(println "-- " (str @cnt))
(conj acc (str @cnt prev))
The argument of your function has the same name as the core function str, so you're shadowing it.

popeye10:01:55

oh crazy! me ... I did not noticed I am passing arg as str 😞

delaguardo10:01:58

clj-kondo can report shadowed vars, it is really good to have it around

oly10:01:17

Hi, been having major issues with an uberjar I have built, I have traced it down to com.novemberain/pantomime conflicting with connection pooling in some way, I am aware I can do clj -X:deps tree is there a way to get the tree for a specific dependency, like a grep but for the matching dep from root so I can see the specific tree ? Also curious what the next step would be to figure out why this is only an issue with the uberjar and how to resolve it in general. Basically at the remove and build the requirement and it works add it back in and the connection pooling start up fails again.

oly10:01:39

I guess its likely to be related to commons-* libraries

jumar16:01:40

Don't you see the "sub-tree" in the output of clj -X:deps tree ? I'm not sure but maybe the uberjar build is picking different versions of the conflicting dependencies than the regular (REPL) run. Afaik, there's no generic solution for dependency conflicts - you need to find what libraries are causing problems and then fix their versions to ones that work. Do you have an exact error message? That would be a good start...

oly16:01:19

I do see a tree, what I was kind of after a a filter to show anything under pantomime and exclude the rest, mainly so I can do it for connection-pool and pantomime and do a diff on the trees to check the libs and versions.

oly16:01:17

In the end I dropped pantomime and extracted the one function that I actually used so I could use an updated Tika, which pantomime is a wrapper around

oly16:01:36

"java.lang.NoSuchMethodError: 'void com.mchange.v2.cfg.BasicMultiPropertiesConfig.<init>(java.lang.String[], java.util.List)" This is the actual error I get but I am not sure how to figure out the lib causing it, kind figure it my knowledge or perhaps this is just how it is in java land

jumar16:01:00

You can google that class and check its history, notably the constructor it seems to mention: https://github.com/swaldman/mchange-commons-java/blame/master/src/main/java/com/mchange/v2/cfg/BasicMultiPropertiesConfig.java#L107-L110 And always check the stacktrace too - it will help you understand who's trying to invoke that.

jumar16:01:23

Because this constructor seems to be package-private so only classes in the same package are allowed to call it.

oly16:01:25

I think the thing I find most perplexing is pantomime has nothing to do with databases and does not include mchange as a dependency, so I don't get why it would make the method unavailable all of a sudden,

jumar16:01:59

Because mchange-commons-java is used by other libraries, e.g. c3p0 connection pool: https://mvnrepository.com/artifact/com.mchange/mchange-commons-java/usages

jumar16:01:10

That dependency tree should make it obvious what artifacts are using mchange-commons-java . And, again, the stacktrace would help you determine where the problem happens.

jumar16:01:45

My guess is that it's a transitive dependency of apache tika: https://github.com/michaelklishin/pantomime/blob/master/project.clj#L8-L9

oly17:01:10

Thanks, I will take another look not sure if I got a stack trace, kind of moved on but I would like a better understanding in case I hit this error again, that was part of my hoping there would be a way to shrink clj -X:deps tree to show just the deps I am interested in, I know I can copy and past but felt like there may have been a paramater to do that kind of filter.

slk50011:01:56

How to get number of elements after :when modifier ? (defn list-tags [items] [:ul (doall (for [item items :when (str/includes? item @value) ] [:li item]))])

daveliepmann11:01:16

If you need a total, I'd do something like (->> items (filter #(str/includes? % @value)) count). Is that what you're trying to do?

slk50011:01:01

hmm as you see it's mixed with hiccup so function will return html. I was thinking I could get count from this function and save it to same atom value. Or do I have to write another function just with count? Seems like a waste.

slk50011:01:57

or maybe I should first just filter the items and save to it atom value, get count save to another value, and finally pass it do hiccup function ?

daveliepmann11:01:55

Saving it to an atom value would be fairly un-idiomatic, I think

daveliepmann11:01:52

What's supposed to be in each :li?

slk50011:01:40

just text in eg. word 'airplane'

daveliepmann11:01:28

So what's the count for? I guess it's used elsewhere?

slk50011:01:52

there is a list of item and input if I press letter 'b' it will show all items with that letter so I want also a count of how many elements was found with letter 'b'

daveliepmann11:01:04

I'd let-bind the filtered elements, count it, show the count, and use the same bound name in the :ul code.

slk50011:01:17

hmm so how this example would like look ?

daveliepmann11:01:21

something like

(let [results (filter #(str/includes? % @value)
                      items)]
  [:p "# results:" (count results)]
  [:ul (doall (for [result results]
                [:li result]))])

❤️ 4
daveliepmann12:01:21

Happy to help ❤️

zakkor12:01:42

Is it possible to make a library globally available no matter which file I’m in? For example I want to use a defn spec macro but I don’t want to import it in every file where I’d use it (since this is a defn replacement that means literally all files)

zakkor13:01:44

The classic Clojure answer, then 😄

lispyclouds13:01:41

@U03EC9KU17H here i would think in terms of "if i were to make this into a lib, how does the user know defn means something else?" its simpler to be more explicit

zakkor13:01:03

right, but I don't want to make this into a lib

zakkor13:01:05

in some scenarios it's useful to have things defined globally. Like how things in clojure.core are useful globally in all projects, I want to be able to decide for my own project which things are useful globally, so I don't need to :refer [div h1 h2 h3 h4 h5 h6 p ul ol li ...] in every single file

lispyclouds13:01:12

sure, but if there is a process that allows this, it wouldve led you into this issue too

daveliepmann13:01:51

> I want to be able to decide for my own project which things are useful globally, so I don't need to :refer [div h1 h2 h3 h4 h5 h6 p ul ol li ...] in every single file In these kinds of scenarios I :refer :all

👎 2
zakkor13:01:50

Guess I can always patch clojure.core, hmmm

😬 2
clojure-spin 2
Amit Gold13:01:43

idk how idiomatic it is, but you can probably require a function do-common-requires then run it. the body of the function would be (require whatever)

practicalli-johnny13:01:01

Is it April 1st already?

😆 4
zakkor13:01:02

Found a great solution:

:repl-options {:init-ns org.my-domain.my-project
               :init (do (in-ns 'clojure.core) (def lol :lol) (in-ns 'org.my-domain.my-project))}
Now lol will be globally available

daveliepmann16:01:38

glad you found a solution that works for you

Empyreans17:01:29

Hey, I am having trouble replacing values in a nested structure performantly. I have a sequence of maps like this: ({:x 0, :y 0, :x-r 500, :y-r 500, :name "F4", :duration 1, :number 1, :color [164 219 207]} ... ) from this sequence, I get each :color vector, and collect them in another sequence: ([164 219 207] [250 255 15] ...) this sequence I send over to an api, where each vector is manipulated and sent back. When I decode that, I have the exact same structure just with different vector values: ([130 210 50] [220 160 30] ...) Now the part where I am stuck. For my original sequence, I just want to replace every one of the old :color vectors with the new ones, so: [164 219 207] becomes [130 210 50] and so on... Performance is key, as these sequences get fairly large. I have something ugly like this, and it is currently my performance bottleneck: (assoc state :cells (map-indexed (fn [i x] (assoc x :color (get (into [] (get-new-color-state state)) i))) (:cells state))) Any help or hints are much appreciated :)

2
daveliepmann17:01:24

Does the API call have to be batched?

escherize17:01:29

(def input
  [{:x 0,
    :y 0,
    :x-r 500,
    :y-r 500,
    :name "F4",
    :duration 1,
    :number 1,
    :color [164 219 207]}
   {:x 0,
    :y 0,
    :x-r 500,
    :y-r 500,
    :name "F4",
    :duration 1,
    :number 1,
    :color [64 19 7]}])

(let [colorz (map :color input)
      f #(map reverse %)
      updated (f colorz)]
  (map (fn [old new] (assoc old :color new))
       colors colorz))

escherize17:01:34

f is the api call

escherize17:01:14

but if it doesn’t have to be batched, it can be a lot simpler, which is what @U05092LD5 is getting at!

daveliepmann17:01:49

I wonder what's going on in get-new-color-state. is that the result of the batched call? Or am I reading this wrong 😄

Empyreans17:01:54

Well does it have to be? I'm not sure actually. The API I was talking about is actually a NodeJS CLI. Before, I tried individual calls with sh from Clojure, but running node color.js 150 20 30ten thousands of times did not seem ideal, as I think there is startup time, so I tried this way. It might be worth a look if other approaches are too convoluted

2
Empyreans17:01:03

Should've provided more context, sorry 🙂 Yes! get-new-color-state is the result of the batched call

Empyreans18:01:10

@U051GFP2V thank you, I will try this.

Empyreans18:01:16

Would really appreciate some feedback on my assumption about calling a node CLI thousands of times seperately. Maybe there is another way ..

escherize18:01:04

Seems like something where a batched job will be faster ^

👍 2
2
daveliepmann18:01:05

I wonder if memoization or better yet caching of these CLI results might speed things along.

skylize20:01:58

Do you control color.js? Seems like you would want to alter that script to export any functions that might be useful as an API. Then you can use require instead of sh, and have everything you need right there.

Empyreans21:01:53

@U90R0EPHA yes, I control color.js. However, the call happens from inside Clojure instead of ClojureScript. I've been wondering about the interop of the two, but my understanding was that I need to communicate over CLI or REST. Can you elaborate? 🙂 I'm not terribly familiar with JavaScript tooling.

Empyreans21:01:59

@U05092LD5 thanks for the hint! I'm not yet familiar with these mechanisms in Clojure, but the transformation of the color is a process that happens relatively frequently, so the values that I get over the API will get replaced again eventually

Empyreans21:01:50

More context: I use both ClojureScript and Clojure for this project. The main application (Quil) runs on Clojure in realtime, and I need to use JavaScript for some libraries that work with color and MIDI files, so there is a lot of tight interaction between the two. Non-realtime data I transmit via transit, realtime data via the node CLI.

skylize00:01:45

In that case, I would likely suggest a long-running Node process that accepts API requests to pass through to the JS libraries. The most straightforward way to do that (mainly due to ease of copying code from the internet) would be an http server. You could alternatively use the https://nodejs.org/api/net.html to serve TCP or IPC. I suspect IPC sockets will give the best latency characteristics, which sounds potentially important for your use case. Maybe it would make sense to write the server/daemon in CLJS (instead of JS) to reduce context switching between languages? You are right that spinning up multiple Node processes will add a lot of overhead, including startup time for each process. So I don't think communicating through the shell is doing you any favors here. Removing the startup time of a Node process is going to wildly outweigh any perf tips anyone could offer you for transforming a Map.

didibus05:01:23

Did @U051GFP2V’s solution speed it up?

Empyreans12:01:54

I could try out @U051GFP2Vs solution and it works great, even with CLI calls. Thank you erscherize, thank you all for your time! 🙂

Empyreans12:01:43

@U90R0EPHA I've thought about going the TCP route but was hesitant because of the overhead for client server communication. I am wondering about performance specifics. Is it really a difference if I choose IPC over TCP? The communication is running on localhost after all, I thought there is some kind of loopback mechanism allowing for transfer up to gigabytes per second.

skylize14:01:52

At least on Linux, IPC is going to have slightly less system overhead and more optimized kernel paths. That doesn't really say whether this has a meaningful difference for you. Your comments indicate this is a music app. If that music is just playback, I doubt you would notice a difference, even if there is one. "Live" music, on the other hand, is extremely sensitive to latency, in which case ... still maybe. You would need perf testing to know for sure if the benefit of IPC is real for you. But, if nothing else, it should give you a bit of extra headroom for other sources of latency that might crop up.

🙏 2