Fork me on GitHub
#beginners
<
2022-10-12
>
valerauko13:10:25

are there any plans of clojure support for jetbrains fleet?

Daniel Craig13:10:04

There is the Cursive plugin

valerauko13:10:34

that works with fleet?

Daniel Craig13:10:11

oh Fleet is a new thing, I'm sorry, I wasn't aware of this

Daniel Craig13:10:35

If Fleet supports LSP then clojure-lsp would work right?

valerauko14:10:07

i have no idea! i just got the email notifying me it's now public, but i couldn't find anything in-app (or in documentation) about plugins or similar

Epidiah Ravachol18:10:14

I got a WebSocket to work!

๐ŸŽ‰ 9
Epidiah Ravachol18:10:59

I have no questions or concerns. Just feeling the joy of doing something I've never done before and had to share.

โค๏ธ 2
catjam 1
teodorlu20:10:12

Embrace it! ๐Ÿ˜

2
sheluchin19:10:31

I want to make a stateful transducer that merges consecutive maps that meet some criteria. The merge is done in a specific way. I'm trying to model my code after dedupe but I'm getting tripped up by the transients. It works with into but not with transduce. I'll post the snippet in ๐Ÿงต if someone can take a look please ๐Ÿ™

sheluchin19:10:36

(defn merge-maps-on-lang
  ([k]
   (fn [rf]
     (let [pv (volatile! ::none)]
       (fn
         ([] (rf))
         ([result] (rf result))
         ([result input]
          (let [prior @pv]
            (vreset! pv input)
            ; (sc.api/spy)
            (if (= (k prior) (k input))
              (conj! (pop! result)
                     (assoc (dissoc (doto input tap>) :lang)
                            ;; CAUTION: won't work to merge more than 2
                            :langs [(:lang prior) (:lang input)]))
              (rf result (-> input
                             (assoc :langs [(:lang input)])
                             (dissoc :lang))))))))))
  ([f coll] (sequence (merge-maps-on-lang f) coll)))

(let [d [{:name 1
          :lang :clj}
         {:name 1
          :lang :cljs}
         {:name 2
          :lang :clj}]
      ;; adds a new item out of order (by :name))
      unsorted (conj d {:name 1 :lang :cljs})
      three-langs (assoc d 2 {:name 1
                              :lang :x})]
  (tests
   "If they are sorted by :name, they will get merged on :lang"
   (into [] (merge-maps-on-lang :name) d)
   := [{:name 1
        :langs [:clj :cljs]}
       {:name 2
        :langs [:clj]}]
   "Unsorted collections produce unexpected results; not supported"
    ;; should be 2 since only 2 distinct :name values
   (count (into [] (merge-maps-on-lang :name) unsorted))
   := 3))

sheluchin19:10:23

(let [d [{:name 1
          :lang :clj}
         {:name 1
          :lang :cljs}
         {:name 2
          :lang :clj}]]
  (transduce (merge-maps-on-lang :name)
             conj!
             d))
This part doesn't work as intended. I can call persistent! on the result, but that's not good, because I want to be able to compose this transducer with others using comp.

seancorfield19:10:17

I don't see a call to transient in there...?

ghadi19:10:58

never write your algo with transients initially

ghadi19:10:35

write it using ordinary persistent data first, then sprinkle in transients as a final step

sheluchin19:10:52

Sorry, I meant volatile!..

seancorfield19:10:10

Then I'm confused why you mention persistent!?

seancorfield19:10:57

I'm also confused as to why you have conj! and pop! when there are no transients involved @UPWHQK562?

sheluchin19:10:31

I started off applying this transducer with into like the tests in the first snippet show. They didn't work at first, so I debugged it and figured out that it if I do use conj! and pop! there, I get the desired result. When I tried to use roughly the equivalent operation using transduce instead of into as the second snippet shows, thing stopped working. I have some confusion here myself, clearly. I know into uses transients under the hood and transduce does not, so I suspect my confusion starts somewhere around there. Now, I think I wrongly assumed my first snippet was proving that it was working correctly, and then I used that as the basis for this trial:

(transduce (merge-maps-on-lang :name)
             (completing
              conj!
              persistent!)
             (transient [])
             d)
and while that produces the correct result in this particular case, I think I need to backtrack a little. As it is, it doesn't seem to comp properly.

rolt20:10:54

you shouldn't manipulate result like that. A solution is to have a second volatile to accumulate the result of the current lang let's call it acc in your 2-arity:

(if (or (= (k prior) (k input)) (empty @acc))
  (do (add-the-language acc input)
      result
  (let [res @acc]
    (reset! acc nil)
    (rf result @acc))
and in your 1-arity
(if (seq @acc)
  (rf result @acc)
  result
something like that

rolt20:10:17

check out partition-all for instance

rolt20:10:32

you basically want a mix of partition-all and dedupe

seancorfield20:10:36

@UPWHQK562 Which version of Clojure are you using?

rolt20:10:36

you're example with transduce would (probably) work if you did:

([] (transient (rf)))
         ([result] (persistent! (rf result)))
but it will never work with comp like a proper xform

seancorfield20:10:29

OK, I wanted to check you weren't tripping over https://clojure.atlassian.net/browse/CLJ-2556

๐Ÿ‘ 1
rolt20:10:15

the idea is that you "emit" the accumulated value only when the language change or when you've consumed the input. That way the following xform can work on emitted value. What you were doing was mutating the result itself and the following xform of the comp has probably consumed it already by the time you do that (not sure emit is the right term)

rolt20:10:47

actually: partition-by source code is the perfect example

sheluchin20:10:47

@U02F0C62TC1 Thank you for the pointers and explanation. I think that is sufficient for me to give it another shot with a fresh brain tomorrow morning. I understand what you're getting at by not manipulating the result in place and partition-by is indeed conceptually more similar to what I'm trying to achieve.

sheluchin14:10:22

I think I have it working, but if someone has time, please give me a quick sanity check:

(defn merge-maps-on-lang
  "Stateful transducer to merge maps on :lang.

  Input must be sorted by `k`.

  If two consecutive maps have the same `k`, merge them by:
  - adding a new :langs key which combines the :lang of each map
  - keeping the first map, except for its :lang"
  ([k]
   (fn [rf]
     (let [pv (volatile! ::none)
           item (volatile! {})]
       (fn
         ([] (rf))
         ([result]
          (let [result (if (seq @item)
                         (let [v @item]
                           ;;clear first!
                           (vreset! item {})
                           (unreduced (rf result v)))
                         result)]
            (rf result)))
         ([result input]
          (let [prior @pv]
            (vreset! pv input)
            (if (or (= (k prior) (k input))
                    (= @item {}))
              (let [n (-> input
                          (dissoc :lang)
                          ;; CAUTION: won't work to merge more than 2
                          (assoc :langs [(:lang prior) (:lang input)]))]
                (vreset! item n)
                result)
              ;; :name has changed
              (let [v @item]
                (vreset! item {})
                (let [ret (rf result v)]
                  (when-not (reduced? ret)
                    (vreset! item (-> input
                                      (assoc :langs [(:lang input)])
                                      (dissoc :lang))))
                  ret))))))))))

rolt11:10:01

it's a good exercice to learn transducers, but if it's production code i'd simply use (comp (partition-by :lang) (map build-lang))