This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2018-12-12
Channels
- # adventofcode (135)
- # announcements (1)
- # beginners (192)
- # boot (5)
- # calva (130)
- # cider (42)
- # cljdoc (4)
- # cljs-dev (6)
- # cljsrn (3)
- # clojure (222)
- # clojure-europe (2)
- # clojure-greece (5)
- # clojure-italy (24)
- # clojure-nl (23)
- # clojure-russia (1)
- # clojure-spec (6)
- # clojure-uk (67)
- # clojurescript (35)
- # cursive (39)
- # datomic (61)
- # emacs (17)
- # figwheel (3)
- # figwheel-main (2)
- # fulcro (12)
- # hyperfiddle (10)
- # juxt (3)
- # leiningen (10)
- # nrepl (35)
- # off-topic (34)
- # onyx (3)
- # pathom (6)
- # quil (5)
- # re-frame (29)
- # reitit (6)
- # ring (1)
- # ring-swagger (8)
- # shadow-cljs (37)
- # spacemacs (9)
- # sql (9)
- # tools-deps (24)
- # unrepl (1)
- # vim (1)
@dfcarpenter The related blog article : http://tonsky.me/blog/datascript-chat/
Thanks!
how can i get paginated results of an atom?
for example, maybe i have an atom of maps that each have a :timestamp 10110 key with unique timestamps. i'd like to sort them, and i'd like to return the first 20, and then on another request the next 20 (21-40) and then again the next 20 (41-60) etc
the atom part doesn't really effect any of this at all (partition-all 20 (sort-by :timestamp @foo))
to split it between requests you can combine that with drop
or nth
please elaborate 😄
user=> (nth (partition-all 20 (range)) 10000)
(200000 200001 200002 200003 200004 200005 200006 200007 200008 200009 200010 200011 200012 200013 200014 200015 200016 200017 200018 200019)
that's the 10000th group of 20 results from the list of all numbers starting at 0
Hiredman put it very well one time. Atom is an interface with two operations: swap and reset. Your question is orthogonal to the use of an atom
@noisesmith awesome!!!!!!!!!!!!
i suppose. i just equate atom with "where the data lives" which is not 100% accurate but in practice it is applicable
You just care that you have some sequential thing. The atom says nothing about what it contains
Why should I prefer using partial over an anonymous function? For example:
#(+ 5 %)
vs
(partial + 5)
The former is more succinct and arguably clearer to me, given that the % symbol communicates the expectation of an argument as well as its location.I ask because [this](https://github.com/bbatsov/clojure-style-guide) style guide states:
;; good
(map #(+ 5 %) (range 1 10))
;; (arguably) better
(map (partial + 5) (range 1 10))
I’d say that’s in dispute. I think everyone on the core team would tell you anonymous functions are preferred to partial.
One difference to be aware of is the effective arity of the resulting function
user=> (#(+ 5 %) 1 2 3 4)
ArityException Wrong number of args (4) passed to: user/eval149/fn--150 clojure.lang.AFn.throwArity (AFn.java:429)
user=> ((partial + 5) 1 2 3 4)
15
user=>
To do the same with an anonymous function, you would need (#(apply + 5 %&) 1 2 3 4)
Is there any performance difference between the two approaches to be aware of? Coming from a bit of ML background I tend to use partial
more often, surprised to hear that anonymous functions are preferred by the core team
I very much doubt that any performance differences are worth worrying about.
If you have performance-critical code, you're more likely to be focused on boxed vs primitive math and vector vs primitive array and stuff like that I suspect.
I got a weird problem in my simple crawler code https://github.com/stardiviner/clojurians-slack-log/blob/master/src/clojurians_slack_log/core.clj#L87 . Here is the problem function. When I use CIDER debug, it can spit text to file, but when I execute code to invoke function as below the function definiction in (comment ..)
block, it has no content write into file. Don't know how to figure this out. Can someone check my code out to help me?
@stardiviner Most likely because you're using map
for side-effecting functions. You either want doseq
or run!
here.
map
is lazy so it won't actually do anything unless something forces the result to be realized all the way through (which CIDER debugging is doing, I'm sure). But your -main
won't do anything because nothing will cause that map
call to be realized.
As written, channel-messages
won't do anything when run (unless you're forcing realization via CIDER debugging). You have a call to map
, and then a call to prn
. So that entire map
expression will essentially be thrown away and not realized, because only the last expression in a function (or in a let) is returned and only that value could be realized (by a caller).
Does that help @stardiviner?
I'm start project REPL to testing. Let me take a try.
@seancorfield I changed code into this
clojure
(defn channel-messages
"Extract all message a in channel's all dates and write into channel-named file."
[{channel-name :name channel-url :url}]
(map #(doseq [message (channel-date-log %)]
(let [filename (str "log_files/" channel-name ".txt")]
(io/make-parents filename)
(spit filename
(compose-message message)
:append true)
;; FIXME: debug spit every message?
(prn "spit: ..")))
(map :url (channel-log-dates channel-url)))
(prn (format "Channel [%s] exported." channel-name)))
Still does not work.Maybe I should use (type ..)
around all (map )
forms to know which one return a lazy sequence, then I need to use doseq
or run!
on it?
map is always lazy, there's no need to check the type. It gets forced if something else consumes its result. That's the only variable.
Your outer map
will not be realized.
If you change both map
on the first line of channel-messages
to run!
-- and the map
in -main
to run!
, that should work.
So it will become (run! #(run! (fn [message] ...
And in -main
: (run! channel-messages (all-channels))
Use your advice, the code works now. How can I avoid this trap in future? Because when I write the code, I have not even realized this lazy sequence probelm.
map
is always lazy. If you are trying to do side-effects, it is always the wrong function.
for
is also lazy, so watch out for that too.
Got it.
Lots of Clojure core functions are lazy -- always check the docstrings!
@seancorfield What about doall
? It is better?
hi all, is there any library on server-side, which kind of provides a single store with subscriptions with deduplication
I have a function that removes an element from a list based on some criteria, it returns the same data structure, so I can chain multiple function invocations like (remove :el (remove :el2 list))
. I now would like to re-use the function with a list of elements to remove. How can I achieve that?
Is there a learning Clojure by examples video/tutorial/blog or everything else you can recomend?
@nikola.kasev is it something you can't do with filter? https://clojuredocs.org/clojure.core/filter
I'll try to tweak the function to take a list to remove, so it will work with one or many
something like this maybe?
user=> (defn remove-elems [list elems]
(remove #(contains? elems %) list))
#'user/remove-elems
user=> (remove-elems [:a :b :c] #{:a :c})
(:b)
I'm not sure I understand
filter takes two parameters, a filter function that returns boolean and a collection
(filter pred coll)
pred is applied to each element in coll
and if the result is true then the element is kept, otherwise it's not included in the output
So, if you write a function to replace pred with, you don't need to mess with single vs multiple elements
What am I missing?
thank you for your ideas, I didn't know remove
existed. I should just read the complete documentation 😂
@ali.ebadian https://www.braveclojure.com/foreword/ is how I started learning Clojure
@nikola I started with that but as i am retard i need to do till ii learn
@ali.ebadian clojure koans is perfect for absolute beginners: https://github.com/functional-koans/clojure-koans and if you don't want to setup anything locally there's http://clojurescriptkoans.com/ (not 100% up to date with clojure-koans master)
@pavlos That looks cool
Hey all again, here with another basic silly question, why do we use [] with let?
We dont use them for bindings in def
def defines a single binding, right? let can handle multiple pairs, so it has to know where the binding block ends
Oh I didnt know it does multiple onse, ive only seen it used to bind one thing
(let [s "Something" "someting else"])
(let [s "something" t "something else"])
"key" "value" pairs
oh thats what I meant
usually written as such in order to be easier on the eyes:
(let [s "something"
t "something else"])
btw did this prefix notation made life make sense to you too?
clojuredocs is your friend 😉 https://clojuredocs.org/clojure.core/let
its fucking fantastic
thanks btw
^ Along with the prefix notation, the fact that LISPs define their syntax as interpretation of data structures instead of text is decidedly simpler IMO.
Is anyone else slightly frustrated with put off by the inconsistencies of threading?
(-> "sTring" lower-case)
-> "string"
(-> "sTring" (lower-case))
-> "string"
(-> "sTring" @#'random-private-function)
-> arity exception
(-> "sTring" #(clojure.string/lower-case %))
-> CompilerException
(-> "sTring" (#(clojure.string/lower-case %)))
-> "string"
I understand your point. But keeping in mind that it is a macro (and understanding what it does), it is not inconsistent then.
Yeah I think I understand why you must enclose anonymous functions and private functions in parentheses but parentheses being optional in some cases and mandatory in others is still inconsistent behaviour. Not sure it could/should be "fixed". I can live with it obviously but it's one of my first pet peeves with clojure! 😄
Thanks!
“…but parentheses being optional in some cases and mandatory in others is still inconsistent behaviour.” yes, you are right. you are welcome!
threading is not a semantic operation, it's a syntactic one. Thanks to this fact you can do very strange things with thread forms.
user=> (->> (+ a b) (let [a 10 b 31]))
41
Just me then? ok 😛
what you're ignoring here is that #()
expands to (fn [..] ..)
and @x
expands to (deref x)
so you see how (-> foo @x)
doesn't translate to (@x foo)
, but to (-> foo (deref x))
and then (deref x foo)
I see, that clears things up a lot, thanks
However, from the user's perspective, sometimes parentheses are optional and in other cases they are mandatory
Yeah, I suppose 😛
Is there a point to not having macros like these expand to expressions with enclosing parentheses?
Yeah, I meant the "problematic" cases specifically, not the general case
(e.g. anonymous and private functions)
what you are proposing would require semantic understanding of the code being transformed
I see, you've been really helpful! Thanks a lot!
heh, hopefully 😉
I have a spec like so
(s/def ::x int?)
(s/def ::y int?)
(s/def ::z int?)
(s/def ::coord (s/keys :req [::x ::y ::z]))
if I try to validate it with a map like {:x 0 :y 0 :z 0}
, I get an error that my input map doesn't have :my-spec-ns/x
, :my-spec-ns/y
, nor :my-spec-ns/z
in it
When defining specs, I understand you need to use fully qualified keywords. But when actually using them to test data.. all the keywords in my maps need to be fully qualified too?
For good measure, here is the function and function spec (e is where the s/def
above are)
(defn distance-squared
"Returns the Euclidean squared distance between the coordinates"
[c1 c2]
(let [{x1 :x y1 :y z1 :z} c1
{x2 :x y2 :y z2 :z} c2
dx (- x1 x2)
dy (- y1 y2)
dz (- z1 z2)]
(+ (* dx dx) (* dy dy) (* dz dz))))
(s/fdef distance-squared
:args (s/cat :c1 ::e/coord :c2 ::e/coord)
:ret int?)
Guys, would this alignment of code
(s/consume-async (partial message-handler exc) socket)
(s/on-closed socket (partial closed-handler exc))
(s/on-drained socket (partial drained-handler exc))
be preferred before this one?
(s/consume-async (partial message-handler exc) socket)
(s/on-closed socket (partial closed-handler exc))
(s/on-drained socket (partial drained-handler exc))
Personally, I prefer the second one, - less rules / maintenance but I've seen both
A little, it kind of trades readability for typing/maintenance if things change name.
(sorta beginner) I have an old project I wanted to pick up again. I've updated my installed version of lein, and when I try lein repl
I'm getting an error Exception in thread "main" java.lang.AssertionError: Assert failed: transport-fn
. This is Leiningen 2.8.2 on Java 1.8.0_25
there's some turmoil right now with the latest release of lein which came out yesterday. if you do lein upgrade 2.8.1
you should have smooth sailing
https://github.com/technomancy/leiningen/issues/2497 - new bug in 2.8.2
there's a migration from clojure.tools.nrepl to a newer community version and this migration is proving a little tricky at the moment
this is not something you should have to worry about 🙂 you're in the beginners channel and things "should just work"
yeah well...otoh I'm restarting a slack bot project that I had working a year ago so there's beginner and then there's beginner 😉
for sure. it just happened on the day after there was an update to a build tool that hasn't seen an update in a long time 🙂
not sure what you mean. if you came back to c after a bug in gcc was released, or elm and a bug in 0.19, or haskell and a bug in cabal or stack, or rust and a bug in rustc or cargo, etc. every language has some build tooling that just needs to work. and there was a bug (now resolved) in lein which is a pain and unfortunate but it is fixed
Sorry I just meant is there something about Clojure that lends itself to experiencing that problem more frequently than others or is it more of a freak chance?
i'm not sure Clojure does experience that more frequently. Lein has been rock solid for a long time it seems. a single bug the day of release when swapping out really low level core stuff once in a few years doesn't seem like the sky is falling.
Agreed. It’s a small bug that flew into the window of opportunity while moving to greener pastures. I am fairly new to the lang and was interested in your experience is all 🙂
cider has had some issues with stability due to an internal reworking of connections but things are smoothing out
@jeff.bachtel You won the lottery…but instead of winning money it’s a broken release.
this is normal for CIDER, I guess it will be normal for nrepl too now
oh - that's lein not nrepl, my bad
The fix got merged just now. maybe a new leiningen release soon
I am trying to just hold onto the printed value of:
Is there an obvious way to bind the printed time value as opposed to the value of the expression?
with-out-str will capture everything a form prints to *out*
(ins)user=> (def t (with-out-str (time (+ 1 1))))
#'user/t
(ins)user=> t
"\"Elapsed time: 0.008802 msecs\"\n"
@noisesmith Perfect! Thank you, sir!
that'll depend if you are actually just storing a schema or migrations, how those migrations are run, etc
Can anyone share some code (from github perhaps) or blog article that shows idomatic clojure error handling?
I find that I write these beautiful simple functions but then struggle at adding error handling to them 😕
How can I locate the position of a regex match in Clojure? I'm looking for functions that search for patterns in strings, doesn't have to be regex
@nikola.kasev If you just want to find the index of a substring in another string, look at clojure.string/index-of
(from memory -- but clojure.string
is where you'll find all the native string functions... except for the few in clojure.core
🙂 )
@ramblurr I'm not sure there is One True Idiomatic Way for error handling in Clojure. It's going to depend on the situation. Do you just need to know something "failed" but otherwise get back a computed result? Do you need to know why something failed? Is it an "expected" failure or are you asking about "exceptional" failures?
@nikola.kasev you can do this with re-matcher
user=> (let [m (re-matcher #"a" "bbbabbb")] (.find m) (.start m))
3
If I understand correctly, .find is calling the method of the Java object that the function re-matcher
returns?
right, m is a Matcher
user=> (type (re-matcher #"a" "bbbabbb"))
java.util.regex.Matcher
The api is easy to find via google. The find method looks for the first match (if any), the start method tells you the starting index of the most recent match.
In a lot of cases where you either get a computed (non-`nil`) result or "failure", returning nil
is often good enough -- and a lot of Clojure functions behave that way (so you can use if-let
or when-let
with the result).
If you want to return a successful value or an error, returning either {:result <whatever>}
or {:error "It blew up!"}
can be useful so you can use destructuring
(let [{:keys [result error]} (some-computation)]
(if error
(report error)
(process result)))
I'm trying to run a basic lein project and I keep getting the error
`
Error occurred during initialization of boot layer
java.lang.module.FindException: Module java.xml.bind not found
Even through I have :jvm-opts ["--add-modules" "java.xml.bind"]
in my lein project.clj. I'm on JDK 10. No idea why this is occuring@dfcarpenter You may need to upgrade your version of Leiningen...
I just left jvm-opts []
*empty and it worked