This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2023-04-13
Channels
- # aleph (3)
- # announcements (2)
- # babashka (15)
- # beginners (84)
- # biff (28)
- # calva (2)
- # cherry (1)
- # clj-kondo (24)
- # clojure (69)
- # clojure-austin (35)
- # clojure-brasil (7)
- # clojure-conj (2)
- # clojure-europe (83)
- # clojure-losangeles (1)
- # clojure-nl (1)
- # clojure-norway (13)
- # clojure-portugal (5)
- # clojure-turkiye (2)
- # clojurescript (25)
- # css (4)
- # cursive (11)
- # data-science (26)
- # datahike (4)
- # datalevin (2)
- # emacs (19)
- # gratitude (1)
- # honeysql (1)
- # hyperfiddle (45)
- # introduce-yourself (5)
- # lsp (53)
- # malli (8)
- # mid-cities-meetup (1)
- # nrepl (19)
- # pathom (23)
- # practicalli (2)
- # proletarian (1)
- # rdf (2)
- # reagent (28)
- # releases (4)
- # shadow-cljs (11)
- # sql (13)
- # uncomplicate (6)
- # vim (7)
- # xtdb (3)
Hey folks. I recently saw @alexmiller wrote that eduction
is eager (most recently in https://ask.clojure.org/index.php/12847/use-transducers-clojure-core-lazy-sequence-transformations?show=12848#a12848, and on slack https://clojurians.slack.com/archives/C053AK3F9/p1567446198032000 and https://clojurians.slack.com/archives/C053AK3F9/p1567447768035100?thread_ts=1567446353.034500&cid=C053AK3F9). I'm somewhat confused by this, in my experience it only does as much work as it is asked to do.
I'd appreciate some insight, as it appears I'm misunderstanding something either with eduction, or with what the things Alex wrote mean. Not sure if Alex himself is around to chime in perhaps?
Example in the thread.
(let [ed (->> (range 500000)
#_(into [])
(eduction (map #(doto % print)))
(eduction (map #(doto % (->> (str " ") println)))))]
(println "taking 3")
(->> (into [] (take 3) ed)
(println "taken 3:"))
(println "getting first")
(->> (first ed)
(println "got first:"))
(println "reducing first")
(->> (reduce (comp reduced {}) nil ed)
(println "reduced first:")))
taking 3
0 0
1 1
2 2
taken 3: [0 1 2]
getting first
0 0
1 1
2 2
3 3
4 4
5 5
6 6
7 7
8 8
9 9
10 10
11 11
12 12
13 13
14 14
15 15
16 16
17 17
18 18
19 19
20 20
21 21
22 22
23 23
24 24
25 25
26 26
27 27
28 28
29 29
30 30
31 31
32 32
got first: 0
reducing first
0 0
reduced first: 0
=> nil
While there is difference in how much is calculated, it appears that difference is due to how the eduction is consumed.
Results appear to be the same regardless of whether the starting input is a lazy sequence or a vector (uncomment the into)It occurred to me whether perhaps eduction
eagerly consumes its input collection as opposed to eagerly running the calculations within so I did another test where I added prints when the input is realized:
(let [new-input (fn []
(->> (range 100)
(map #(doto % (->> (println " init:"))))))
xf1 (map #(doto % (->> (print " processing:"))))
xf2 (map #(doto % (->> (println " "))))
ed (->> (new-input)
(eduction xf1)
(eduction xf2))]
(println "=================================================\nTaking 3")
(->> (into [] (take 3) ed)
(println "Taken 3:"))
(println "=================================================\nTaking 3 again")
(->> (into [] (take 3) ed)
(println "Taken 3 again:"))
(println "\n=================================================\nGetting first")
(->> (first ed)
(println "Got first:"))
(println "\n=================================================\nGetting first again")
(->> (first ed)
(println "Got first again:"))
(println "\n=================================================\nReducing first")
(->> (reduce (comp reduced {}) nil ed)
(println "Reduced first:"))
(println "\n=================================================\nTransducing first without eduction from new input")
(->> (new-input)
(transduce (comp xf1 xf2) (completing (comp reduced {})) nil)
(println "Transduced:")))
=================================================
Taking 3
init: 0
init: 1
init: 2
init: 3
init: 4
init: 5
init: 6
init: 7
init: 8
init: 9
init: 10
init: 11
init: 12
init: 13
init: 14
init: 15
init: 16
init: 17
init: 18
init: 19
init: 20
init: 21
init: 22
init: 23
init: 24
init: 25
init: 26
init: 27
init: 28
init: 29
init: 30
init: 31
processing: 0 0
processing: 1 1
processing: 2 2
Taken 3: [0 1 2]
=================================================
Taking 3 again
processing: 0 0
processing: 1 1
processing: 2 2
Taken 3 again: [0 1 2]
=================================================
Getting first
processing: 0 0
processing: 1 1
processing: 2 2
processing: 3 3
processing: 4 4
processing: 5 5
processing: 6 6
processing: 7 7
processing: 8 8
processing: 9 9
processing: 10 10
processing: 11 11
processing: 12 12
processing: 13 13
processing: 14 14
processing: 15 15
processing: 16 16
processing: 17 17
processing: 18 18
processing: 19 19
processing: 20 20
processing: 21 21
processing: 22 22
processing: 23 23
processing: 24 24
processing: 25 25
processing: 26 26
processing: 27 27
processing: 28 28
processing: 29 29
processing: 30 30
processing: 31 31
init: 32
init: 33
init: 34
init: 35
init: 36
init: 37
init: 38
init: 39
init: 40
init: 41
init: 42
init: 43
init: 44
init: 45
init: 46
init: 47
init: 48
init: 49
init: 50
init: 51
init: 52
init: 53
init: 54
init: 55
init: 56
init: 57
init: 58
init: 59
init: 60
init: 61
init: 62
init: 63
processing: 32 32
Got first: 0
=================================================
Getting first again
processing: 0 0
processing: 1 1
processing: 2 2
processing: 3 3
processing: 4 4
processing: 5 5
processing: 6 6
processing: 7 7
processing: 8 8
processing: 9 9
processing: 10 10
processing: 11 11
processing: 12 12
processing: 13 13
processing: 14 14
processing: 15 15
processing: 16 16
processing: 17 17
processing: 18 18
processing: 19 19
processing: 20 20
processing: 21 21
processing: 22 22
processing: 23 23
processing: 24 24
processing: 25 25
processing: 26 26
processing: 27 27
processing: 28 28
processing: 29 29
processing: 30 30
processing: 31 31
processing: 32 32
Got first again: 0
=================================================
Reducing first
processing: 0 0
Reduced first: 0
=================================================
Transducing first without eduction from new input
init: 0
init: 1
init: 2
init: 3
init: 4
init: 5
init: 6
init: 7
init: 8
init: 9
init: 10
init: 11
init: 12
init: 13
init: 14
init: 15
init: 16
init: 17
init: 18
init: 19
init: 20
init: 21
init: 22
init: 23
init: 24
init: 25
init: 26
init: 27
init: 28
init: 29
init: 30
init: 31
processing: 0 0
Transduced: 0
=> nil
But it appears that isn't the case either (this is on 1.11.1, chunking doesn't seem to be working as I had expected in 1.12)
On the first take 3
the first 32 elements of the input are realized, then the first 3 are processed by the eduction(s).
On the second take 3
enough elements of the input are realized already so no further init happens, only the re-processing of the first 3 as per the eduction docs.
first
wants to look at the first 33 elements for some reason so on the first invocation the second 32 element chunk is realized, then the first 33 elements are processed. On the second invocation, all the elements needed are already realized so eduction reprocesses the first 33.
Reducing first
only needs a single element and that's what eduction reprocesses so.
For a comparison I reimplemented the reducing first with transduce
to see how it works without the eduction and it doesn't seem any different.
sorry, I was really referring to reduce in that sentence
Thanks for the response Alex 🙂 Does it also apply to this comment on slack? > eduction is pretty specialized in that it is a delayed eager evaluation https://clojurians.slack.com/archives/C053AK3F9/p1567446198032000
it is delayed
it is often used in eager scenarios
no, it's iterator based, but often used with reduce, which is eager
sorry, have been too busy to reply to the other ask question yet
Not at all, I honestly really appreciate your approachability and how you interact with the community! I re-raised the question here mainly because my understanding of what you had stated was at odds with how I had understood eduction. I had refactored code in multiple places to use it once I got to know eduction and part of the reason for those refactorings was the capability of eduction to only calculate as many elements as absolutely necessary. I feared that if I misunderstood eduction these might cause problems and wanted to ask for community wisdom to help decide whether I need to revisit those places in code. Thank you again for your time!
SOLVED Hello -- I stumbled on something that works, but I’m curious about how it works. I needed a function to be named Integer
or something close to it, but that collides with the built-in java.lang.Integer
. I thought about Integer-
or Integer_
to sidestep the collision (I didn’t want -Integer
as that connotes “private”). Then I recalled auto-gensyms in macros, and wrote something like
(defn Integer# [x] {:type 'Integer, :bytes 4, :value x})
(Integer# 42)
and it works fine! I’m not sure whether Integer#
is actually an auto-gensymmed name, however, because my usage is not in a macro. I’m not sure how to find out, actually, because I’m not sure how to dig inside the symbol Integer#
to find out what Clojure thinks it’s doing with it.
I’m not losing sleep over this, because it works, but I am curious and would be grateful for some tricks to help me dig into symbols and figure out what’s inside, or for some simpleminded explanation of my stumble-upon :)x#
is just a symbol. It will turn into some other symbol only inside the syntax quote.
user=> `x#
x__2__auto__
it is not auto-gensymmed. defn itself is a macro so you can expand it to the code:
(def Integer# (fn* ([x] {:type 'Integer, :bytes 4, :value x})))
and because def is a special form Integer#
stays as is.
However, this symbol might cause problems if will use it inside of syntax quote:
(defmacro foo []
`(do
(prn "!!!")
(prn (Integer# 1))))
(foo) ;; expands to (do (prn "!!!") (prn (Integer__11986__auto__ 1)))
;; => Syntax error compiling at (src/dev/dotfox/matchete.cljc:295:1).
;; Unable to resolve symbol: Integer__11986__auto__ in this context
appreciate it :) ty
@U03CZA5A539 You can use (ns-unmap *ns* 'Integer)
and then simply call your function Integer
. But sometimes people like to call these constructor functions ->Something
, so maybe ->Integer
isn't too bad either
@U04V15CAJ I like ->Something
! I do need java.lang.Integer
in the same namespace as my Integer
constructor function, so unmapping java.lang.Integer
wouldn't work off-the-cuff. Maybe I could rename java.lang.Integer
instead? If so, how would I do that?
You could always refer to it by its full name.
But please don't shadow it. It's much better to use ->Integer
or any other variation if possible.
great info from both of you! this is going to solve my problem
’lo all. I’ve run into a change in behavior between jdk 17 and jdk 19 with respect to coercion and java interop (I think). I’ve narrowed it down to whether or not a bind a value to a var: e.g., (all on Clojure 1.11.1)
(Thread/sleep (int 100)) ;; => works in jdk17 and jdk19
(def int-millis (int 100))
(Thread/sleep int-millis) ;; => works in jdk17, blows up in jdk19 with IllegalArgumentException: No matching method sleep found taking 1 args
% cat thread-sleep.clj
(println (format "clojure-version %s" (clojure-version)))
(println (format "java.version %s" (System/getProperty "java.version")))
(println "(Thread/sleep (int 100))")
(Thread/sleep (int 100))
(def int-millis (int 100))
(println "(Thread/sleep int-millis)")
(Thread/sleep int-millis)
(println "done")
jdk17:
% clj -Srepro -M thread-sleep.clj
clojure-version 1.11.1
java.version 17.0.6
(Thread/sleep (int 100))
(Thread/sleep int-millis)
done
jdk19:
% clj -Srepro -M thread-sleep.clj
clojure-version 1.11.1
java.version 19.0.2
(Thread/sleep (int 100))
(Thread/sleep int-millis)
Execution error (IllegalArgumentException) at user/eval11 (thread-sleep.clj:7).
No matching method sleep found taking 1 args
They added a new overload to sleep that takes a Duration and that is screwing with clojures ability to determine what method you are trying to call
If you turn on reflection warnings you'll see it complain about not being able to figure it out
I think I've opened issues against several repos about reflection warnings from that change (we keep a pretty close eye on reflection warnings at work).
@U04V15CAJ Is there anything in clj-kondo that can check whether I’ve remembered to enable reflection warnings for namespaces where I’ve done java interop?
yes: https://github.com/clj-kondo/clj-kondo/blob/master/doc/linters.md#warn-on-reflection
@alexmiller Maybe Clojure should have a sleep
function to avoid this interop/reflection issue over several version of the JVM :)
What’s going on with the difference between (Thread/sleep (int 100))
and (Thread/sleep int-millis)
? What’s the difference in how the types are resolved?
@U0EHU1800 The type of a var is never inferred
another shout-out to @U04V15CAJ and clj-kondo. It’s really been life-changing for my development and particularly maintenance of clojure projects. Thank you!
@U0EHU1800 I always use clj-kondo, but when doing interop I often also add https://github.com/jonase/eastwood to my lint pipeline to help find this kind of issue.
I use the clojure compiler for this: https://github.com/http-kit/http-kit/blob/290c7f9cb1d022e453a3f8fc02f18044bed2044a/test-native/bb.edn#L15-L18
along with this: https://github.com/http-kit/http-kit/blob/290c7f9cb1d022e453a3f8fc02f18044bed2044a/test-native/dev/user.clj
we use https://github.com/athos/clj-check at work, which scans for clj files and then loads each one it finds with *warn-on-reflection*
set
SOLVED Hello — this question concerns writing macros to smooth out some multi-specs. Consider the following multi-spec declaration:
(do (defmulti ttype-head ::ttype-head)
(s/def ::asr-ttype-head
(s/multi-spec ttype-head ::ttype-head)))
and the following two instances:
(defmethod ttype-head ::Integer [_]
(s/keys :req [::ttype-head ::bytes-kind ::dimensions]))
(defmethod ttype-head ::Real [_]
(s/keys :req [::ttype-head ::bytes-kind ::dimensions]))
These seem to work fine, but I want to mitigate the repetition. I write:
(defmacro def-ttype-head [it]
`(defmethod ttype-head ~it [_]
(s/keys :req [::ttype-head ::bytes-kind ::dimensions])))
CIDER macro-expand-1 shows everything looking good:
(def-ttype-head ::Integer)
;; =>
(defmethod
ttype-head
:masr.specs/Integer
[_]
(s/keys
:req
[:masr.specs/ttype-head
:masr.specs/bytes-kind
:masr.specs/dimensions]))
But, when I do the full macroexpand, the compiler barfs off with something I don’t understand:
2. Unhandled clojure.lang.ExceptionInfo
Call to clojure.core/fn did not conform to spec.
#:clojure.spec.alpha{:problems ({:path [:fn-tail :arity-1 :params], :reason "Extra input",
...
1. Caused by clojure.lang.Compiler$CompilerException
Error compiling /private/var/folders/cp/df32wpxn1ps8dmn6w_tydwdr0000gn/T/form-init13650237565921167220.clj at (1:8259)
#:clojure.error{:phase :macro-syntax-check, :line 1, :column 8259, :source "/private/var/folders/cp/df32wpxn1ps8dmn6w_tydwdr0000gn/T/form-init13650237565921167220.clj", :symbol clojure.core/fn}
Compiler.java: 6989 clojure.lang.Compiler/checkSpecs
Compiler.java: 7005 clojure.lang.Compiler/macroexpand1
...
I haven’t spotted the error. I’d be grateful for an explanation and - or a fix!Not totally sure it's the only problem, but the _
symbol in the argument list should probably be a gensym _#
(defmacro def-ttype-head [it]
`(defmethod ttype-head ~it [_#]
(s/keys :req [::ttype-head ::bytes-kind ::dimensions])))
I think you can also do:
(s/def ::ttype-head (s/keys :req [::ttype-head ::bytes-kind ::dimensions]))
(defmethod ttype-head ::Integer [_]
::ttype-head)
yeah, it's the _ arg
note that CIDER does not use the error triage and printing system that we spent so much time making in Clojure 1.10, but if you use a clojure.main repl it would have said:
user=> (def-ttype-head ::Integer)
Syntax error macroexpanding clojure.core/fn at (REPL:1:1).
(user/_) - failed: Extra input at: [:fn-tail :arity-1 :params] spec: :clojure.core.specs.alpha/param-list
user/_ - failed: vector? at: [:fn-tail :arity-n :params] spec: :clojure.core.specs.alpha/param-list
which seems a lot more helpful pointing you in the right direction@U7RJTCH6J would the spec ::ttype-head
collide with the multi-spec (s/multi-spec ttype-head ::ttype-head)
?
Yea, it would. You would have to use a different name
roger. Thanks for the sharp reading :)
ASIDE: this discussion helped me a lot. I just wrote a significant new macro and debugged the names given your teachings 🙂
(defmacro def-ttype-sugar [the-head]
`(defn ~the-head
[& {kind# :kind, dimensions# :dimensions,
:or {kind# 4, dimensions# []}}] ;; defaults
(let [cnf# (s/conform
::asr-ttype-head
{::ttype-head
(keyword (str ~the-head))
::bytes-kind kind#,
::dimensions dimensions#})]
(if (s/invalid? cnf#)
(keyword "masr.specs" (str "invalid-" ~the-head))
cnf#))))
that has nested multi-specs :)
what's the stuff you hid in the first ... ?
@alexmiller here are all …
Show: Project-Only All
Hide: Clojure Java REPL Tooling Duplicates (26 frames hidden)
2. Unhandled clojure.lang.Compiler$CompilerException
Error compiling /Users/brian/Documents/GitHub/masr/src/masr/specs.clj at (827:1)
#:clojure.error{:phase :macro-syntax-check,
:line 827,
:column 1,
:source
"/Users/brian/Documents/GitHub/masr/src/masr/specs.clj",
:symbol clojure.core/fn}
Compiler.java: 6989 clojure.lang.Compiler/checkSpecs
Compiler.java: 7005 clojure.lang.Compiler/macroexpand1
Compiler.java: 7110 clojure.lang.Compiler/analyzeSeq
Compiler.java: 6806 clojure.lang.Compiler/analyze
Compiler.java: 6762 clojure.lang.Compiler/analyze
Compiler.java: 1020 clojure.lang.Compiler$HostExpr$Parser/parse
Compiler.java: 7124 clojure.lang.Compiler/analyzeSeq
Compiler.java: 6806 clojure.lang.Compiler/analyze
Compiler.java: 6762 clojure.lang.Compiler/analyze
Compiler.java: 6137 clojure.lang.Compiler$BodyExpr$Parser/parse
Compiler.java: 5479 clojure.lang.Compiler$FnMethod/parse
Compiler.java: 4041 clojure.lang.Compiler$FnExpr/parse
Compiler.java: 7122 clojure.lang.Compiler/analyzeSeq
Compiler.java: 6806 clojure.lang.Compiler/analyze
Compiler.java: 7191 clojure.lang.Compiler/eval
Compiler.java: 7149 clojure.lang.Compiler/eval
core.clj: 3215 clojure.core/eval
core.clj: 3211 clojure.core/eval
interruptible_eval.clj: 87 nrepl.middleware.interruptible-eval/evaluate/fn/fn
AFn.java: 152 clojure.lang.AFn/applyToHelper
AFn.java: 144 clojure.lang.AFn/applyTo
core.clj: 667 clojure.core/apply
core.clj: 1990 clojure.core/with-bindings*
core.clj: 1990 clojure.core/with-bindings*
RestFn.java: 425 clojure.lang.RestFn/invoke
interruptible_eval.clj: 87 nrepl.middleware.interruptible-eval/evaluate/fn
main.clj: 437 clojure.main/repl/read-eval-print/fn
main.clj: 437 clojure.main/repl/read-eval-print
main.clj: 458 clojure.main/repl/fn
main.clj: 458 clojure.main/repl
main.clj: 368 clojure.main/repl
RestFn.java: 1523 clojure.lang.RestFn/invoke
interruptible_eval.clj: 84 nrepl.middleware.interruptible-eval/evaluate
interruptible_eval.clj: 56 nrepl.middleware.interruptible-eval/evaluate
interruptible_eval.clj: 152 nrepl.middleware.interruptible-eval/interruptible-eval/fn/fn
AFn.java: 22 clojure.lang.AFn/run
session.clj: 218 nrepl.middleware.session/session-exec/main-loop/fn
session.clj: 217 nrepl.middleware.session/session-exec/main-loop
AFn.java: 22 clojure.lang.AFn/run
Thread.java: 1589 java.lang.Thread/run
1. Caused by clojure.lang.ExceptionInfo
Call to clojure.core/fn did not conform to spec.
#:clojure.spec.alpha{:problems
({:path [:fn-tail :arity-1 :params],
:reason "Extra input",
:pred
(clojure.spec.alpha/cat
:params
(clojure.spec.alpha/*
:clojure.core.specs.alpha/binding-form)
:var-params
(clojure.spec.alpha/?
(clojure.spec.alpha/cat
:ampersand
#{'&}
:var-form
:clojure.core.specs.alpha/binding-form))),
:val (masr.specs/_),
:via
[:clojure.core.specs.alpha/params+body
:clojure.core.specs.alpha/param-list
:clojure.core.specs.alpha/param-list],
:in [0 0]}
{:path [:fn-tail :arity-n :params],
:pred clojure.core/vector?,
:val masr.specs/_,
:via
[:clojure.core.specs.alpha/params+body
:clojure.core.specs.alpha/params+body
:clojure.core.specs.alpha/params+body
:clojure.core.specs.alpha/param-list
:clojure.core.specs.alpha/param-list],
:in [0 0]}),
:spec
#object[clojure.spec.alpha$regex_spec_impl$reify__2503 0x404deb91 "clojure.spec.alpha$regex_spec_impl$reify__2503@404deb91"],
:value
([masr.specs/_]
(clojure.spec.alpha/keys
:req
[:masr.specs/ttype-head
:masr.specs/bytes-kind
:masr.specs/dimensions])),
:args
([masr.specs/_]
(clojure.spec.alpha/keys
:req
[:masr.specs/ttype-head
:masr.specs/bytes-kind
:masr.specs/dimensions]))}
alpha.clj: 712 clojure.spec.alpha/macroexpand-check
alpha.clj: 704 clojure.spec.alpha/macroexpand-check
AFn.java: 156 clojure.lang.AFn/applyToHelper
AFn.java: 144 clojure.lang.AFn/applyTo
Var.java: 705 clojure.lang.Var/applyTo
Compiler.java: 6987 clojure.lang.Compiler/checkSpecs
Compiler.java: 7005 clojure.lang.Compiler/macroexpand1
Compiler.java: 7110 clojure.lang.Compiler/analyzeSeq
Compiler.java: 6806 clojure.lang.Compiler/analyze
Compiler.java: 6762 clojure.lang.Compiler/analyze
Compiler.java: 1020 clojure.lang.Compiler$HostExpr$Parser/parse
Compiler.java: 7124 clojure.lang.Compiler/analyzeSeq
Compiler.java: 6806 clojure.lang.Compiler/analyze
Compiler.java: 6762 clojure.lang.Compiler/analyze
Compiler.java: 6137 clojure.lang.Compiler$BodyExpr$Parser/parse
Compiler.java: 5479 clojure.lang.Compiler$FnMethod/parse
Compiler.java: 4041 clojure.lang.Compiler$FnExpr/parse
Compiler.java: 7122 clojure.lang.Compiler/analyzeSeq
Compiler.java: 6806 clojure.lang.Compiler/analyze
Compiler.java: 7191 clojure.lang.Compiler/eval
Compiler.java: 7149 clojure.lang.Compiler/eval
core.clj: 3215 clojure.core/eval
core.clj: 3211 clojure.core/eval
interruptible_eval.clj: 87 nrepl.middleware.interruptible-eval/evaluate/fn/fn
AFn.java: 152 clojure.lang.AFn/applyToHelper
AFn.java: 144 clojure.lang.AFn/applyTo
core.clj: 667 clojure.core/apply
core.clj: 1990 clojure.core/with-bindings*
core.clj: 1990 clojure.core/with-bindings*
RestFn.java: 425 clojure.lang.RestFn/invoke
interruptible_eval.clj: 87 nrepl.middleware.interruptible-eval/evaluate/fn
main.clj: 437 clojure.main/repl/read-eval-print/fn
main.clj: 437 clojure.main/repl/read-eval-print
main.clj: 458 clojure.main/repl/fn
main.clj: 458 clojure.main/repl
main.clj: 368 clojure.main/repl
RestFn.java: 1523 clojure.lang.RestFn/invoke
interruptible_eval.clj: 84 nrepl.middleware.interruptible-eval/evaluate
interruptible_eval.clj: 56 nrepl.middleware.interruptible-eval/evaluate
interruptible_eval.clj: 152 nrepl.middleware.interruptible-eval/interruptible-eval/fn/fn
AFn.java: 22 clojure.lang.AFn/run
session.clj: 218 nrepl.middleware.session/session-exec/main-loop/fn
session.clj: 217 nrepl.middleware.session/session-exec/main-loop
AFn.java: 22 clojure.lang.AFn/run
Thread.java: 1589 java.lang.Thread/run
I see the _
in the chaff, there. I might eventually have found it :thinking_face:
clojure.main doing a lot better job surfacing that for you, if only CIDER used it