Fork me on GitHub
#clojure
<
2019-07-22
>
dottedmag08:07:23

Please suggest how to improve this code (and whether it needs to be improved): https://gist.github.com/dottedmag/f38b25718cb151b81ed429312092546b

dottedmag08:07:38

(I tried #code-reviews, but it seems to be deserted at this time of day)

flefik10:07:47

@dottedmag both disj and and conj behave reasonably if you try to add an element that isn’t/is present in the set

flefik10:07:02

so there is no need for the (if (contains? …

flefik10:07:35

user=> (conj #{1 2 3} 2)
#{1 3 2}
user=(disj #{1 3} 2)
#{1 3}

dottedmag10:07:28

@cfeckardt Unfortunately, (conj #{} (peek clojure.lang.PersistentQueue/EMPTY)) gives #{nil}, not #{}

dottedmag10:07:04

So in alloc-fn the if has to stay.

dottedmag10:07:27

In free-fn I'll get a duplicate resource-id in :free if I don't check.

xi10:07:34

defn- declares a private fn

xi10:07:19

Do you mean empty not empty?? L28

dottedmag10:07:05

Right, thanks. Perils of editing right in GitHub 🙂

xi10:07:46

I usually format maps with each kv on a newline, otherwise looks OK

simonkatz10:07:55

Not a big deal, but I prefer defn ^:private over defn-, for consistency with other defining operators. See https://github.com/bbatsov/clojure-style-guide/issues/124#issuecomment-175068673

hjrnunes10:07:12

Does Clojure support reifying interfaces with default methods?

noisesmith17:07:41

you might try proxy with proxy-super (but this has concurrency gotchas...)

ivan minutillo11:07:42

🖐️ im trying to test a ring clojure app with jsoup , but im not able to keep the session while connecting to logged urls. The session is not in a cookie, neither on headers or params Altough there are plenty of resources with jsoup, I am not able to find a way to add a custom session object on a request 😕

4
metacritical15:07:22

I am writing a C# + OpenTK (Open GL) 2D game, i was wondering if someone has any idea about embedding Clojure CLR in a C# app for scripting purposes?

metacritical15:07:23

Yes but its code isnt something i can really understand yet. It is too specific to Unity which i dont know how to work on.

noisesmith17:07:41

there's only two or three methods you actually need to load up and exec clojure (the clr port is of course different, but not massively so...)

noisesmith17:07:24

in fact this code might even work directly:

IFn require = Clojure.var("clojure.core", "require");
require.invoke(Clojure.read("clojure.set"));
with maybe some minor syntax tweaks

noisesmith17:07:05

where the foo.invoke() in host side interop is the same as (foo) in clojure itself

Graham Seyffert17:07:13

@noisesmith why is Clojure.read necessary there? I haven’t had to do that in the past to call Clojure from Java, but maybe I’m just getting lucky?..

noisesmith17:07:42

read takes a string and here returns a symbol - require operates on symbols not strings

Graham Seyffert17:07:06

Ah, I just use symbol manually

noisesmith17:07:08

this is an example that can be generalized to loading arbitrary code and running it, not just running a single file / ns

noisesmith17:07:31

right, symbol vs. read is a stylistic approach I guess

Graham Seyffert17:07:04

Makes sense! Just wanted to make sure i wasn’t missing something 🙂

noisesmith17:07:09

some funny corner cases here :D

=> (= '1 (symbol "1"))
false

noisesmith17:07:40

the symbol of "1" looks like the number 1 but doesn't act like it at all

noisesmith17:07:38

also, imagine using hash-map and symbol and keyword and Integer/parseInt to construct {:a 0 'b 1} as opposed to one call to read on a string

Graham Seyffert17:07:07

Oh yeah no thanks!

Graham Seyffert17:07:42

Luckily my usages of calling Clojure from Java are pretty limited and generally limited to requiring some namespaces and then calling a few functions off of some deftypes

noisesmith17:07:57

yeah, I think that's typical

Graham Seyffert17:07:59

But yeah, if it ever gets beyond that I’ll have to remember that

yuhan17:07:16

Anyone know an easier way of writing this function?

(defn convolute
  [coll]
  (apply map (fn [& xs] (into {} xs))
    (map
      (fn [[k vs]]
        (map (fn [v] [k v]) vs))
      coll)))

(convolute {:a [1 2] :b [3 4]})
;; => ({:a 1, :b 3} {:a 2, :b 4})

noisesmith18:07:34

usually nested map calls can be replaced by for

Graham Seyffert18:07:33

Yeah you can come up with a partition/`interleave` thing here but IMO it looks worse

hiredman18:07:11

(for [m (iterate
         (fn [m]
           (zipmap (keys m)
                   (map rest (vals m))))
         {:a [1 2] :b [3 4]})
      :while (first (first (vals m)))]
  (zipmap (keys m) (map first (vals m))))
I almost like this

Graham Seyffert18:07:20

If you go the for route I think you have to use partition / interleave

hiredman18:07:21

(let [m {:a [1 2] :b [3 4]}]
     (for [i (range (count (first (vals m))))]
       (zipmap (keys m) (for [v (vals m)] (nth v i)))))

8
Graham Seyffert18:07:14

I think the nested sub-sequences here actually make it easier vs. removing the nesting with for

noisesmith18:07:16

another approach

(defn convolute'
  [coll]
  (map (partial into {})
       (apply (partial map list)
              (for [[k vs] coll]
                (for [v vs]
                  [k v])))))

yuhan18:07:03

So many ways of writing the same function! I like @hiredman’s second solution, that seems the closest to being "declarative" without the reader having to reconstruct the control flow and intermediate structures in their head 🙂

Graham Seyffert18:07:59

One thing to watch out with that solution is that if (count (first (vals m)) is larger than the vals of some other item in your map you’ll get an IndexOutOfBounds exception

Graham Seyffert18:07:18

Because of the nth call

noisesmith18:07:58

(min-key count (vals m)) ?

Graham Seyffert18:07:19

(let [m {:a [1 2] :b [3 4] :c [5]}]
  (for [i (range (apply min (mapv count (vals m))))]
    (zipmap (keys m) (for [v (vals m)] (nth v i)))))
=> ({:a 1, :b 3, :c 5})

noisesmith18:07:29

=> (apply min (map count (vals {:a [1 2 3] :b [0] :c [3 4]})))
1

Graham Seyffert18:07:31

I didn’t try min-key

noisesmith18:07:24

min-key fails because it returns the object with the lowest score, not the score itself (and it also needs apply)

hiredman18:07:36

if you must

(let [m {:a [1 2] :b [3 4] :c [5]}
      db (clojure.set/index
          (for [[k vs] m
                [i v] (map-indexed vector vs)]
            {:k k
             :i i
             :v v})
          [:i])]
  (for [i (range (count (first (vals m))))]
    (into {}
          (for [{:keys [k v]} (get db {:i i})]
            [k v]))))

hiredman18:07:58

erm, that range is not correct

hiredman18:07:31

(let [m {:a [1 2] :b [3 4] :c [5]}
      db (clojure.set/index
          (for [[k vs] m
                [i v] (map-indexed vector vs)]
            {:k k
             :i i
             :v v})
          [:i])]
  (for [i (range)
        :let [s (for [{:keys [k v]} (get db {:i i})]
                  [k v])]
        :while (seq s)]
    (into {} s)))

hiredman18:07:28

index on a single value could be group by of course

simonkatz18:07:16

(defn convolute-2 [m]
  (let [[ks vss] [(keys m) (vals m)]]
    (for [vs (apply map list vss)]
      (into {}
            (for [[k v] (map list ks vs)]
              [k v])))))

hiredman18:07:51

(map vector ...)

simonkatz18:07:39

@hiredman Is map vector better than map list? I’ve always used the former, but I copied the latter from something above.

noisesmith18:07:24

you can replace [(keys m) (vals m)] with ((juxt keys vals) m) (whether that's an improvement is up to you)

hiredman18:07:51

the entire inner for could be replaced with map vector

noisesmith18:07:26

right, the body creates the same data that comes into the destructure

simonkatz18:07:14

Ah, yes, of course. Time to go and do something that isn’t coding. 🙂

(defn convolute-2 [m]
  (let [[ks vss] [(keys m) (vals m)]]
    (for [vs (apply map vector vss)]
      (into {} (map vector ks vs)))))

hiredman18:07:14

you could also just stick a when in

hiredman18:07:49

(let [m {:a [1 2] :b [3 4] :c [5]}]
  (for [i (range (count (first (vals m))))]
    (zipmap (keys m) (for [v (vals m) :when (> (count v) i)] (nth v i)))))

noisesmith18:07:27

or :when (contains? v i)

noisesmith18:07:15

or even :while (contains? v i) - that should short circuit properly

hiredman18:07:03

the when is actually broken

hiredman18:07:41

it depends on where in the keys list the key with the shortage of values lies, which a number of the other solutions above do as well