This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2019-05-15
Channels
- # announcements (2)
- # aws (52)
- # beginners (326)
- # cider (24)
- # clara (7)
- # clj-kondo (14)
- # cljs-dev (175)
- # clojure (183)
- # clojure-ecuador (2)
- # clojure-europe (4)
- # clojure-italy (11)
- # clojure-nl (1)
- # clojure-norway (1)
- # clojure-spec (5)
- # clojure-sweden (5)
- # clojure-uk (103)
- # clojurescript (49)
- # cursive (29)
- # data-science (9)
- # datascript (17)
- # datomic (23)
- # emacs (6)
- # events (4)
- # fulcro (19)
- # graalvm (8)
- # graphql (2)
- # hoplon (36)
- # jobs (1)
- # jobs-discuss (92)
- # juxt (3)
- # luminus (10)
- # off-topic (4)
- # pedestal (8)
- # planck (1)
- # re-frame (59)
- # reagent (1)
- # reitit (22)
- # rewrite-clj (8)
- # ring-swagger (3)
- # shadow-cljs (101)
- # spacemacs (15)
- # tools-deps (36)
- # vim (68)
You're thinking of peek
perhaps?
user=> (doc peek)
-------------------------
clojure.core/peek
([coll])
For a list or queue, same as first, for a vector, same as, but much
more efficient than, last. If the collection is empty, returns nil.
nil
user=> (time (apply min-key val m))
"Elapsed time: 842.254296 msecs"
[0 0]
user=> (time (apply min-key peek m))
"Elapsed time: 838.988506 msecs"
[0 0]
user=> (time (apply min-key last m))
"Elapsed time: 2076.809707 msecs"
[0 0]
user=> (time (apply min-key second m))
"Elapsed time: 1531.45713 msecs"
[0 0]
peek performs like val 🙂
second is slow
last is slowercould someone help me understand what’s happening in the combine step of a fold when it’s called with no arguments?
@souenzzo Yup, peek
is special-cased for performance and seems to work just fine on MapEntry
objects too
user=> (let [x (first {:a 1})] (quick-bench (val x)))
Evaluation count : 91382334 in 6 samples of 15230389 calls.
Execution time mean : 4.912437 ns
...
user=> (let [x (first {:a 1})] (quick-bench (peek x)))
Evaluation count : 92238174 in 6 samples of 15373029 calls.
Execution time mean : 4.878394 ns
...
user=> (let [x (first {:a 1})] (quick-bench (last x)))
Evaluation count : 4457562 in 6 samples of 742927 calls.
Execution time mean : 139.544772 ns
...
user=> (let [x (first {:a 1})] (quick-bench (second x)))
Evaluation count : 7887582 in 6 samples of 1314597 calls.
Execution time mean : 76.811493 ns
...
Big difference in this case.@gtzogana Both the reducef and the combinef can be called with no arguments, and should return the identity element.
Since you're looking for a minimum, I would imagine you'd need to return a "maximum" int value so all other values are smaller?
yeah i think that’s where i got stuck, trying to conceptualize what the identity element of an application of min-keys
would be
It's a little odd in your case @gtzogana because your "identity" is to return an arbitrary MapEntry
that contains a maximum value.
Your reducef could look like this:
(defn mk ([] (clojure.lang.MapEntry. nil Long/MAX_VALUE)) ([a x] (min-key val a x)))
and then you'd do
(r/fold mk (seq your-giant-map))
(you need the seq there, otherwise you seem to get a reduce-kv
style call of your reducef with the accumulator, the key, and then value)
(although I wonder if calling seq
here defeats some of what r/fold
can do? I haven't experimented much with it...)
so i’ve got this, which at least returns the correct result
(defn faster-mk [m]
(fold (fn reducef
([] [nil Long/MAX_VALUE])
([a b] (min-key second a b))
([a b c] (min-key second a [b c])))
(seq m)))
Use (clojure.lang.MapEntry. nil Long/MAX_VALUE)
and (clojure.lang.MapEntry. b c)
instead of vectors. Use val
instead of second
. Don't seq
the map.
(defn faster-mk [m]
(fold (fn reducef
([] (clojure.lang.MapEntry. nil Long/MAX_VALUE))
([a b] (min-key val a b))
([a b c] (min-key val a (clojure.lang.MapEntry. b c))))
m))
that should be faster(although when I tested (apply min-key val large-map)
, that was pretty fast)
I tried it with a 20,000 element hash map... I think there's just not enough computation in there to benefit from concurrent execution?
It's an interesting little puzzle 🙂 Happy to help!
Once you get up to 50k, there's more of a difference
user=> (let [v (into {} (take 50000 (repeatedly #(clojure.lang.MapEntry. (rand-int 10000) (rand-int 10000)))))] (quick-bench (apply min-key val v)))
Evaluation count : 1206 in 6 samples of 201 calls.
Execution time mean : 522.122368 µs
...
user=> (let [v (into {} (take 50000 (repeatedly #(clojure.lang.MapEntry. (rand-int 10000) (rand-int 10000)))))] (quick-bench (r/fold mk v)))
Evaluation count : 3420 in 6 samples of 570 calls.
Execution time mean : 172.390103 µs
...
(weirdly I'm seeing more of a difference at 20k than I did before -- benchmarking can be weird)
@gtzogana If you know the performance changes at a particular size, that seems very reasonable.
I'm observing weird behaviour around watches on a ref. Any idea what's wrong? https://gist.github.com/jeroenvandijk/90650bd5d4b8e3ba346e3483bf70d3ab
(let []
(def ^{:flag 1} v 1))
(def ^{:flag 2} v 2)
(add-watch #'v ::listener (fn [_key _ref old-value new-value]
(println "old " old-value ", new" new-value "new-meta " _ref (select-keys (meta _ref) [:flag]))))
Wrapping the def in a let block "fixes" the meta assignmentthe watch function will be called before the var’s value will be set
that doesn't seem to be the case for when it is wrapped in the let block
there is an inconsistency if i didn't make a mistake myself
In this gist you can see a sequence of evaluations that show this inconsistent behaviour
yeah seems there’s a difference indeed
though this probably falls under “that’s not what you’re supposed to use it ffor”
you’re also not guaranteed to have the state of the ref immediately before or after setting the value
yeah i can imagine combining meta, watches and vars is not very common. You might be right 🙂
" Note that an atom’s or ref’s state may have changed again prior to the fn call, so use old/new-state rather than derefing the reference. Note also that watch fns may be called from multiple threads simultaneously”
Sorry for interjecting but I believe we are talking about vars here, not refs.
But note the value of the var (`_ref`) is given to the watch function so it's not doing a deref
No, the _ref
argument is the box the holds a value
Not the value itself
The third and fourth args are old and new values in the box which is the second arg
The value of the ref i mean
yes but the meta data on the var is mutable.
and you’re setting the meta of the var, not of the value
see alter-meta!
Exactly. This meta is on the box (var), not the value in the box
Still doesn't explain the different behaviour in the let though
so (meta some-var)
is doing an implicit deref on some-var
if that's correct
I found the same thing's happening in my REPL:
user=> (declare a)
#'user/a
user=> (add-watch #'a ::listener (fn [_ ref old-val new-val] (pprint {:old-val old-val :new-val new-val :meta (select-keys (meta ref) [:flag])})))
#'user/a
user=> (def ^{:flag 1} a 1)
{:old-val
#object[clojure.lang.Var$Unbound 0x5e26f1ed "Unbound: #'user/a"],
:new-val 1,
:meta {}}
#'user/a
user=> (def ^{:flag 2} a 2)
{:old-val 1, :new-val 2, :meta {:flag 1}}
#'user/a
user=> (def ^{:flag 3} a 3)
{:old-val 2, :new-val 3, :meta {:flag 2}}
#'user/a
user=> (let [] (def ^{:flag 4} a 4))
{:old-val 3, :new-val 4, :meta {:flag 4}}
#'user/a
user=> (def ^{:flag 5} a 5)
{:old-val 4, :new-val 5, :meta {:flag 4}}
#'user/a
user=>
vars have an identity, and you can change the metadata on the var, so yeah it works like deref, but it’s not a deref since the deref gets the associated value instead of the metadata
The symbol some-var
gets evaluated to a var(box) which is then deref'ed and the metadata on that value is given
not really in this case
user=> (def ^{:var-meta 1} a ^{:value-meta 2} {:value-itself 3})
{:old-val 5, :new-val {:value-itself 3}, :meta {:flag 5}}
#'user/a
user=> (meta a)
{:value-meta 2}
user=> (meta #'a)
{:var-meta 1, :line 1, :column 1, :file "NO_SOURCE_PATH", :name a, :ns #object[clojure.lang.Namespace 0x1cf336fd "user"]}
user=>
This might elucidate the difference.
so you’re dealing with the var a
and that var has metadata which can be set directly (by def
in this case)
Thanks guys. I'm trying to make something work for a naive user that set a meta flag on a var so options like alter-meta!
are good, but not what i'm after. Maybe I'll have to manage expectations instead!
I don't think i'm doing explicit deref-ing. It's documented that watches support var's here and they get the var https://clojuredocs.org/clojure.core/add-watch . But if (meta some-var) is an implicit deref you might be right
or maybe i should not rely on the metadata of a var, since like Joost said, it is a mutable reference
If you can, you might want to switch to using the meta data on the value instead.
Depends on your use case of course
I'm doing weird stuff with monitoring vars so I don't have that option for this use case
I'll look into sayid to see how they do this https://github.com/clojure-emacs/sayid/blob/8ea70573e6eb1a0d1a450fd501f38c2cf26ce27f/src/com/billpiel/sayid/trace.clj#L134
any ideas why map-indexed 3 times faster on avg 580 vs 140 ms for 1m entries? (map vector (iterate inc 0) v) (map-indexed #(vector %1 %2) v)
Morning all - I am considering starting a side project to create a clojure to Dart compiler mainly for fun but also with mind to use it to create Flutter apps. What would be the best compiler to work from as a base - Clojure, ClojureScript or CLR? Dart is single threaded so more like JavaScript but the syntax is closer to java/C#. Thoughts?
Hi, I am no expert but I would believe that Cljs is best because it was written after Clojure, with lessons taken from it (e.g. relies heavily on protocols rather than Java interfaces). Also. Clj and CLR emit bytecode while you likely want to emit code. Cljs uses Google Closure heavily - not sure whether there is something similar for Dart.
Hi everybody, I got an issue what I don’t really understand.
I am trying to import a protocol to my namespace and then use satisfies?
to check an instance. In my ns I have the following: (:import taoensso.carmine.connections.IConnectionPool)
, but when I try to use it like (satisfies? IConnectionPool "")
then it throws an NPE
clojure.core/eval core.clj: 3214
...
boot.user$eval34439.invoke : 1
boot.user$eval34439.invokeStatic : 1
clojure.core/satisfies? core_deftype.clj: 569
clojure.core/find-protocol-impl core_deftype.clj: 536
clojure.core/instance? core.clj: 144
java.lang.NullPointerException:
am I doing something wrong?
For use in this way, you should require, not import
It’s a little confusing, but IConnectionPool here is both a var (the protocol map), and an interface (generates internally)
satisfies expects the former
thank you @alexmiller it fixed the problem
thanks @thenonameguy I’ve checked the http://clojuredocs.org first if there is an example like that
but there have been none yet 🙂
what's the latest preferred way to profile Clojure code ? I want something similar to Smalltalk's MessageTally
which returns a tree with time spent at each branch (in Smalltalk's case that's messages in Clojure it would be function applications)
Hello! Is this a known issue with Clojure 1.10.0?
user=> (declare foo)
#'user/foo
user=> (def wrap-foo (partial foo "hello"))
#'user/wrap-foo
user=> (defn foo [s] (print (str s " world!")))
#'user/foo
user=> (wrap-foo)
Execution error (IllegalStateException) at user/eval2006 (REPL:1).
Attempting to call unbound fn: #'user/foo
so when evaluated the "foo" passed to partial, the result is a special object designed to catch these kind of bugs when it is invoked
Clojure 1.10.0
user=> (declare foo)
#'user/foo
user=> (def wrap-foo (partial (var foo) "hello"))
#'user/wrap-foo
user=> (defn foo [s] (print (str s " world!")))
#'user/foo
user=> (wrap-foo)
hello world!nil
Just to show what @hiredman is saying even more clear. If instead of foo
you refer to the var, it works how you want it to.The var here defers the look up.
user=> (declare foo)
#'user/foo
user=> (def f #(foo "bar"))
#'user/f
user=> (defn foo [s] (str "foo" s))
#'user/foo
user=> (f)
"foobar"
user=>
using partial at the top level like without understanding that partial is just a function, so it's arguments are evaluated like any other function at call time is a common source of bugs
@urzds Not sure why you are writing code like this. If you are just playing around with things, sure. But I wouldn't expect to see declare in actual code.
user=> (def x 1)
#'user/x
user=> (def f (partial + x))
#'user/f
user=> (def x 3)
#'user/x
user=> (f 0)
1
user=>
Thanks. So I generally should use var
in this case? Or is there a better / more recommended way?
@urzds what are you trying to do? just define things out of order (that's the usual usage of declare)
usually instead of using (var x)
explicitly we use the reader macro #'x
which expands to the same thing
@jimmy I have a map that contains coercion functions as values (and the keys they shall be applied to as keys). And one of these coercion functions calls other functions that will eventually make use the the coercion map again. So in theory this setup is cyclic, but in practice it is not, because the data structures it operates on are not cyclic.
@urzds if the functions can all be defined in one form, there's letfn
that allows cyclical references between the functions it creates in local scope
another variant is to have every fn take an argument containing a hash-map that includes all the other fns - that way, you can even add more functions at runtime or from another namespace
So the data structure I operate on looks like this:
[{:foo 1
:bar {:foo 2 ...}}
{:foo 3 ...}]
And in these few instances where the object contains a "sub object" in the :bar key, I want to apply the same coercions to the sub object, which is why I need access to the coercion map.sounds like it could be a job for clojure.walk/prewalk
with a function testing for map entries and calling a multimethod on key
Hm, thanks. I never considered this to be a full walk, because :foo 2, the object under :bar, is of a different type that never contains other sub objects.
prewalk is a blunt tool, agreed, but it might lead to simpler code
one more note: I specify prewalk rather than postwalk specifically because you can't test for map-entries in postwalk (the code turns them into two element vectors, and that works fine for hash-map, but it removes a distinction you likely need to check for, prewalk avoids that issue)
Thanks @jimmy, @hiredman, @noisesmith!
I am trying to create a vector-based zipper where the children of a node are (next node). For navigating around, this works fine:
(defn vec2zip
"Return a zipper where the children are (next node)."
[root]
(z/zipper vector? next (fn [n c] (into n c)) root))
But editing doesn't work as I'd expect:
(-> (vec2zip [:X [:A] [:B] [:C]]) z/down (z/insert-child [:a]) z/root)
[:X [:A] [:B] [:C] [:A [:a]] [:B] [:C]]
Am I doing something stupid? I tried to attach metadata in the children and make-node functions, but it doesn't seem to stick. Might that be the problem?@peterd have you looked at z/vector-zip
? - or is the point to implement this from scratch as an exercise?
how so?
@noisesmith the children don't 'have names', if that makes sense.
@hiredman Yeah, I have that working just fine with {:n :X :c [{:n :A} {:n :B} {:n :C}]} for example. Just gets a bit busy.
(defn map2zip
"Return a zipper for a map representing a plan."
[root]
(z/zipper map? :c (fn [n c] (assoc n :c (vec c))) root))
Thanks @noisesmith and @hiredman. I've tried everything I can think of. Given what I've seen, I agree that maps are the best approach.
Hello, what is the equivalent of :java-source-paths
of leiningen in tools.deps? Some of my code is in Java and I really wanna use it as it is.
tools.deps does not support java compilation
you can use it in combination with javac etc if you want that to work
or you can split your project into java-only and clojure-only parts and have the latter depend on the former
ah okay. Thanks for the info @alexmiller Is java compilation planned soon? Really love using tools.deps!
not planned - deps does a) dependency resolution, b) classpath building, c) program launching
got it. thanks again 😄
Are there any books on Clojure that explain it's philosophy as opposed to just teaching syntax? I am interested in learning about choices Rich made and trade-offs resulting from those choices. I know he talks about it in his talks but I would like (if it exists) to have a single place with all this information, so to say. To understand Clojure, not only to learn it
probably the best you'll get for that are either talks by Rich, or the http://clojure.org reference pages, or in book form - Programming Clojure (written by Stu Halloway and latest revised by me, both of us working with Rich)
It's amazing to get an answer in less than a minute, and especially from you Alex! 🙂 Thank you! I love this community ❤️
https://github.com/matthiasn/talk-transcripts/tree/master/Hickey_Rich <- more time efficient than watching videos
sibling dirs contain other relevant stuff probably
or https://www.youtube.com/playlist?list=PLZdCLR02grLrEwKaZv-5QbUzK0zGKOOcr :)
that was missing some videos so I added them and reverse date sorted
the talk Rich did at JavaOne years ago is actually a pretty great intro https://www.youtube.com/watch?v=VSdnJDO-xdg
not in learning the language, but why the language exists
Also @U0DNK8PV0 you can get quite a good sense of philosophy and the "Why?" of Clojure from The Joy Of Clojure book, if you haven't already read that.
Asking for the most ideomatic approach: suppose we have a mutual recursion
(defn a [x] (if .. (b x))
(defn b [x] (if ...(a x))
Now I’d like to inject another arg y
into a
but in order to do so I also have to:
1) change b
arity (in case b call a not directly but there’s a longer call chain it gets tedious).
2) Another variant is introducing a dynamic var and do binding
across everything (but it becomes opaque and var always means toplevel)
3) in case x is even not {}
I could handle it with metadata containing y
(looks like a hack)
What would you prefer? (please vote) Am I missing yet another approach?
In short: 1=explicit pass args | 2=implicit | 3=hackSorry, maybe I expressed myself not clearly, I know how to define/declare, the question is actually -> pass something explicit or implicit
Well regardless of the problem context, if you want functions calling each other on the same level, usually something is wrong. It’s always good to call functions from top to bottom.
/ a
foo
\ b
My bet is you just need a proper data/context shape + (recur)
like
(defn foo
[ctx]
(recur
(cond (condition)
:a (a ctx)
:b (b ctx))))
(defn a
[ctx]
(assoc ctx ...))
(defn b
[ctx]
(assoc ctx ...))
can you write out the two implementations?
See here https://github.com/DomainDrivenArchitecture/smeagol/blob/master/src/smeagol/formatting.clj#L159
I’d like to add an arg to process-text
maybe ideal situation is when x is a {}
and passing around (assoc x)
is very cool, but in this case it’s not 😕
For this specific example you linked to I would get rid of those auxiliary functions. The 4 arguments passed around add a lot of cognitive overhead and the body of these functions don't do much.
yep, a valid point 👍 but still, it’s not always an option to incorporate everything inside a single scope
but I also aware that recur is more optimal than trampolines (which are even omitted in this case -> stackoverflow possible)
still, people often argue about scala implicits but they’re really handy instead of passing smth around
I agree, I use dynamic vars when I have a context to pass everywhere or to pass through a long list of functions that do nothing with it other than forwarding it.
Even when there is non-trivial state that may be changed by users, passing explicit args is better IMHO. We can get back the convenience of not having to pass args each time by implementing Component and/or Integrant's abstractions.
maybe ideal situation is when x is a {}
and passing around (assoc x)
is very cool, but in this case it’s not 😕
Given it's mutual recursion with two fns colocated next to each other in the same file and calling each other directly, I'd add an explicit argument (and maybe another arity so clients can maintain their present interface)
yeah, preserving interface makes 1. even more verbose 😞 this situation makes me think one more time that only passing hashes around rocks
hey ya'll, what are people using for repl autocomplete etc when using just clj
instead of leiningen? Is reply still common?
use another main 🙂 https://github.com/bhauman/rebel-readline (uses compliment
library for autocomplete, same as reply afair)
still, people often argue about scala implicits but they’re really handy instead of passing smth around