Fork me on GitHub
#clojure
<
2023-04-18
>
restenb07:04:53

i have a fn that takes an input then further input in kv-pairs like this (a-fn [input-1 & input-pairs] ...) and a map of the pairs like {:k1 v1 :k2 v2 ...} . looking for a way to turn the map kv's into the function call (a-fn input-1 k1 v1 k2 v2 ...)

p-himik07:04:07

(apply a-fn input-1 (apply concat the-map)).

🚀 2
rolt08:04:20

if you're writing a-fn consider using (defn a-fn [input-1 & {:as input-pairs}] ...) that way you can use both: https://clojure.org/news/2021/03/18/apis-serving-people-and-programs

restenb08:04:45

a-fn actually was a macro 😊

p-himik08:04:10

You can't do it with a macro then. Unless you're doing it in another macro.

p-himik08:04:42

If it's the latter, then (a-fn input-1 ~@(apply concat the-map))` or something like that - depending on the outer macro.

slipset11:04:17

user> (def xs [1 2 3])
;; => #'user/xs
user> (map identity xs)
;; => (1 2 3)
user> (map #'identity xs)
;; => (1 2 3)
user> (map identity #'xs)
Error printing return value (IllegalArgumentException) at clojure.lang.RT/seqFrom (RT.java:557).
Don't know how to create ISeq from: clojure.lang.Var
user> 
In this example there is no need to var quote, but if xs were defined as private (using metadata) in another ns, it would have been nice. I’m totally fine with “Don’t do that”, but I’m curious as to why I can’t map over a var-quoted thing?

p-himik11:04:24

You can use #'identity only because vars are callable.

p-himik11:04:06

The Var class implements IFn and delegates the implementation to the wrapped function, if it's a function.

p-himik11:04:31

You can still use @#'xs.

slipset11:04:16

So, given that:

user> (def s #{1})
;; => #'user/s
user> (filter #'s [1 2 3])
;; => (1)
user> (filter #'s #'s)
Error printing return value (IllegalArgumentException) at clojure.lang.RT/seqFrom (RT.java:557).
Don't know how to create ISeq from: clojure.lang.Var
user> 
Totally makes sense.

slipset11:04:36

Thanks a lot for the explanation 🙂

👍 4
2
reefersleep13:04:27

Is there like a tome of "Curious Implementation Details" with stuff like this for Clojure? Or are you it? 😄

Ed13:04:46

I think I recall Alex Miller saying something about a Clojure Puzzlers book, in the vein of the Java Puzzlers one 😉

🤓 2
ken18:04:42

I'm trying to parse clojure codes given as string. I need to find function if there and make sure that is exactly which is from clojure.core . But I can't resolve if

(ns-resolve 'clojure.core 'if)
;; => nil 
Had a glance at the clojure.core source but I didn't find there a declaration of if (`def` too). Any way to resolve if? And where is it defined?

ken18:04:13

Got it. So we can't resolve them. Is there any way to determine a symbol is special form?

dpsutton18:04:19

i’d look into using clj-kondo programatically to get the analysis

ken20:04:31

@U11BV7MTK I didn't know clj-kondo can be used as parser/analyzer. Should play with it)

ken20:04:32

@U0739PUFQ This will help me, thanks!

rschmukler18:04:24

So, I am not quite sure where this belongs but I stumbled across an interesting issue while working with nrepl. Basically, changing the clojure send-off executor the the new OpenJDK 19 Loom executor can seemingly cause inlined dependencies that have a static def for a delay to somehow never call the body when the delay is dereferenced. I am unsure if this is an issue with OpenJDK 19 or Clojure (or perhaps most possible, me doing something silly) but I have managed to create a minimal reproduction in https://github.com/rschmukler/haystack-interaction. I found this because haystack (an inlined dependency of cider-nrepl) happens to have a static delay and makes use of pmap (which under the hood uses the executor set by set-send-off-executor! and I have a project where I used the Executors/newVirtualThreadPerTask as the send-off! executor. Anyway, this might be so fringe that the answer is "who cares" but again, it potentially suggests some sort of weird interaction between Clojure, potentially inlined deps (I couldn't reproduce it if I wrote similar code w/o an inline dep) and the new OpenJDK loom executors. Happy to provide whatever other context if anyone has ideas.

rschmukler22:04:38

So, after a day of debugging it looks like this is most likely an issue with Loom more than anything. Calling set-agent-send-off-executor! will cause pmap to use that executor. Deeply nested spawning of threads seems to lock up loom easily (ie. a few level of pmap nesting). Below is a code snippet that can be used to see it:

(defn ppmap
  [f coll]
  (->> coll
       (mapv
         (fn [x]
           (let [cf (java.util.concurrent.CompletableFuture.)]
             (Thread/startVirtualThread
               (bound-fn []
                 (try
                   (.complete cf (f x))
                   (catch Exception e
                     (.completeExceptionally cf e)))))
             cf)))
       (map deref)))

(let [n 4]
   (->> (range n)
        (ppmap
          (fn [_]
            (->> (range n)
                 (ppmap (fn [_]
                          (->> (range n)
                               (ppmap (fn [_]
                                        (ppmap identity (range n))))
                               (apply concat)
                               (into #{}))))
                 (apply concat)
                 (into #{}))))
        (apply concat)
        (into #{})))

vemv10:10:43

(haystack contributor here) I just found this :) Interesting insights! This seems another reason why we shouldn't add pmap in Haystack and sibling projects. Don't hesitate to create issues in Haystack/etc as you find them.

timrichardt21:04:55

Why doesn't some return a transducer when no collection is provided?

dpsutton21:04:12

it returns the first item that matches a predicate. It doesn’t really pass items on in a chain. Not sure what the transducer would do. Does the cgrand lib have a version?

timrichardt21:04:33

Right, I was confused. https://github.com/cgrand/xforms/blob/master/src/net/cgrand/xforms.cljc#L769 Here is what I meant, some is the reducing function, not a part of the transducers. Thanks!