This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2019-10-11
Channels
- # announcements (6)
- # architecture (9)
- # beginners (120)
- # calva (13)
- # cider (28)
- # clj-kondo (8)
- # cljs-dev (7)
- # clojure (113)
- # clojure-europe (13)
- # clojure-italy (7)
- # clojure-nl (9)
- # clojure-spec (44)
- # clojure-uk (7)
- # clojuredesign-podcast (15)
- # clojurescript (18)
- # cursive (9)
- # data-science (3)
- # datomic (32)
- # defnpodcast (1)
- # events (2)
- # fulcro (6)
- # jobs (1)
- # kaocha (5)
- # london-clojurians (2)
- # luminus (2)
- # nyc (2)
- # off-topic (54)
- # ring (6)
- # shadow-cljs (136)
- # sql (1)
- # testing (2)
- # tools-deps (64)
- # vim (83)
(I guess there's a small chance that -> form is incorrect because ($ 1) or ($ :type) might not be a map lookup, but I find it unlikely it would be anything else in context)
Also (since this is one of my "pet peeves"), as->
is designed to be used inside ->
for cases where the value you're passing in is neither the first nor last argument (for the latter case you can nest ->>
inside ->
). So it is more normal to see:
(-> exp
(f 2 3)
(as-> x (g 1 x 3))
(h 2 3)
(->> (map foo)))
@noisesmith Yes, that was an example from the Clojure docs.
http://Clojuredocs.org are not official clojure docs, so you need to be dubious of what you find there
A lot of what is there is good, but the quality does vary
In Python one can strip characters from the end of a string with 'foo/'.rstrip('/')
. Is (clojure.string/replace "foo/" #"/$" "")
the Right Way to do that in Clojure?
If you only want to strip one /
off, that would work. #"/+$"
would match one or more /
at the end of the string.
I don't know whether I'd say regex is the Right Way but it's either that or checking (str/ends-with? s "/")
and then returning (subs s 0 (dec (count s)))
which may be clearer or not 🙂 but might well be slower.
Looks like the if
/ ends-with?
/ subs
approach is faster if that matters @clojurians-slack100?
user=> (time (dotimes [n 100000] (str/replace foo #"/$" "")))
"Elapsed time: 91.607793 msecs"
nil
user=> (time (dotimes [n 100000] (if (str/ends-with? foo "/") (subs foo 0 (dec (count foo))) foo)))
"Elapsed time: 33.313469 msecs"
nil
(I ran it several times and that's about the average -- but all the usual caveats about micro-benchmarks apply 🙂 )
Very cool, thanks @seancorfield!
I tend towards the more readable one for single cases, so I guess I'll stick with str/replace
🙂
@adamfranzen check if you're in the same namespace as the one you defined foo in
Just need a confirmation that JMM is weakly ordered and such order of reads is allowed for a non-synchronized code.
Hi Clojurians, I have a simple problem for which I’m trying to find an idiomatic solution - basically transforming a map of maps into a vector of vectors
(fun {{:a 1} {:b 1}} )
;;=> [[:a 1] [:b 1]]
CORRECTION
A list of maps, instead of a map of maps
(fun ({:a 1} {:b 1}))
Here's one way to do it
(reduce-kv (fn [acc k v] (reduce into acc [(vec k) (vec v)])) [] {{:a 1} {:b 1}})
This is too much fun
user=> (mapcat #(mapcat vec %) m)
([:a 1] [:b 1])
user=> (into [] (mapcat (partial mapcat vec)) m)
[[:a 1] [:b 1]]
Hehe, nice @UCW9TUDNK 👍
So, when I added this to the actual pipeline it also flattens the structure :thinking_face:
I think this because the sort-by
actually returns a list
{:a 1} {:b 1}}
was the example you gave. Is this a valid input too: {{:a 1 :b 2} {:b 1 :c 3 :d 4} {:e 1} {:f 2}}
. If yes, what's the expected output?
yeah, my bad about the example - I kind assumed that sort-by
would return a map. Here’s how I built upon the wonderful solutions by @UCW9TUDNK
But wrapping this into a hash-map
makes me loose the sorting as well.
@U883WCP5Z, na, it’s basically a map version of idents which I’m expecting
I’m not following the above. If the problem definition is still to take a list of maps to a vector of vectors, you might be able to rely on the fact that a map entry is a vector and do something simpler like:
(mapv first '({:a 1} {:b 1}))

But I think @U04VDQDDY has found the most idiomatic solution [=
Ah, yes @U04VDQDDY I ended up building upon what @UCW9TUDNK mentioned earlier and mapping an anonymous function over the list - but this simplied it to just first
- thanks 👍
`(apply concat '({:a 1} {:b 1}))` I think I missed important context in this thread - but this works for the original input / output and = as a test
When reading clojure code I don't seem to see any explicit error handling like try/catch
or whatever (I'm really naive on this stuff for any language, not just clojure). I've explored using :pre
and :post
conditions a little bit.
But I feel like this quote from Alex Miller on a current r/clojure discussion might hint at the "idiomatic" philosophy: "In general, Clojure is aggressively polymorphic (over nil, etc) and with a bit of familiarity with common patterns, it's feasible to write Clojure code that doesn't throw errors at all. "
Can someone go in more depth of what this might mean? What would those patterns look like? What is your approach to error handling and where would you guide a junior dev about it? (that one might be too broad, apologies)
looking up a key that isn't found doesn't throw, it just returns nil (or the default you specified, if any), and most functions do something useful if you give them nil instead of an expected data type, the overall idiomatic style is less concerned with detecting and rejecting error conditions and more with maximally general data operations that do a reasonable default with unexpected data if possible
ok. that makes sense. Could you give me an example of a reasonable default? Like just "ask for input" again or something, or just carry on with the program in some way?
I only expect to see try
around host interop (where classes from java land are more eager to throw) and I only expect throw
to happen at the edge of the system, when detecting invalid reuqests from other systems or invalid states in the interaction with some other server
Awesome. I snipped Alex Miller's quote where he seems to be in agreement with you on that.
usually idiomatic clojure is built on the clojure built in data functions, which treat nil as an empty list where appropriate, and return nil when doing lookup on nil or an a key or index that isn't found
so you get those defaults for free from the stdlib
and so your function logic just accounts for if you get those "free" nils instead of the value you probably wanted?
I let the built ins handle the nils up to the edge (when possible), and the edge (that is, the top level process code or the entry point where a request comes in) can give a reasonable error to the client / programmer
right, precisely
that reasonable error part. Is that like a
if (nil? something)
"error: you need to do this"
(else-do-stuff something)
yeah - it's probably data returned to a client so they can retry / fix their code, plus a log to aid debugging
no throw even needed
better yet, instead of just using a conditional on nil, you can use a spec on the input or result and use that to construct a meaningful messsage
though throwing an ex-info
hash map where the data can be inspected on catch is sometimes simpler - depends on the shape of the application code
It's a good practice to have a top-level error handler - like in a webapp; when everything else fails you catch the error, log it and return a (somewhat) friendly error message.
Also, if you create new threads it's wors to install UncaughtExceptionHandler
(see here https://stuartsierra.com/2015/05/27/clojure-uncaught-exceptions)
For things like future
that doesn't work though so you may want to wrap body in try-catch or use logged-future
(https://github.com/ptaoussanis/timbre#logging).
the reason it doesn't work for future is that there's an intentional design decision not to throw until the value of the future is accessed (by dereffing) - this is a behavior of the underlying class that comes with the jvm, instead of a try/catch or logging-future you can ensure that a finished future is eventually dereffed if you care about failures
Looking for some regex help (I think). I want to split a string like "2AB3cD4e"
into ["2A" "B" "3c" "D" "4e"]
so with some repl experimentation I have (re-seq #"\d[a-zA-Z]" text)
but that leaves out all single letters like "B"
or "D"
. Various other attempts give me different things too but I can't quite get what I want. Any help? Would you approach this altogether differently?
(re-seq #"\d?[a-zA-Z]" text)
?
So regex is pretty universal across languages, right? If I find a general regex tutorial on the interwebs it should be directly applicable or should I learn a specific java way?
the basics are pretty universal, the details or advanced usage usually depend on which flavor you're using
but Clojure just re-uses Java's so that is the one to look at
https://docs.oracle.com/en/java/javase/13/docs/api/java.base/java/util/regex/Pattern.html
I am not an authority on this, but having seen quite a few regex languages over the years, the meanings of these characters is good to learn, and common across all or most of them: [ ] + * ? | . After that things like \s \S \d I use most commonly. After that I don't trust that I will be doing enough with that one regex library that I will remember what is common across them and what is not.
This web site has way more detail than I ever want to learn on the subject, but is probably a good resource if you want to (a) learn the basics, (b) find some cool tools that show interactive color highlighting of a regex against sample text, to more quickly debug your regexes, and (c) dig into the gory details of the differences between different libraries, if you want to. https://www.regular-expressions.info/
awesome. I'll bookmark it. I also was recently suggested this one: https://regexone.com/ and it looks good too.
As I may have already strongly hinted at, I would recommend learning the basics of regex's first, and if you start getting into things where you are using other features, e.g. lookahead, lookbehind, etc., consider instead using a more powerful parser, e.g. for Clojure something like instaparse
Howdy y'all, anybody got a problem? 😄
How hard of a problem are you looking for? 🙂
hmm, what's your hardest one?
Prove that P=NP, or that P!=NP 🙂
i meant a useful problem
But I'll try to show that P = NP.
That would be cool.
I wonder why they decided to make clojure map destructuring work like “value key, value key” instead of the arguably more intuitive “key value key value”:
user=> (let [{a :a b :b c :c} {:a 1 :b 2 :c 3}] [a b c])
[1 2 3]
I intuitively reached for
user=> (let [{:a a :b b :c c} {:a 1 :b 2 :c 3}] [a b c])
[1 2 3]
Edit, sorry the last one is:
user=> (let [{:a a :b b :c c} {:a 1 :b 2 :c 3}] [a b c])
Syntax error macroexpanding clojure.core/let at (REPL:1:1).
Because bindings typically have symbol then expression.
(I think that's why)
If all the keys match the symbols you want, you can use (let [{:keys [a b c]} ,,,] ,,,)
at first I thought it was so that you could put any function on the right hand side, that keywords were just a special case, but:
user=> (let [{a :a b :b c :c size count} {:a 1 :b 2 :c 3}] [a b c size])
[1 2 3 nil]
I had suspected it would return [1 2 3 3]
oh welluser=> (let [{a 'foo b :bar c "quux"} {'foo 42 :bar 13 "quux" 99}] [a b c])
[42 13 99]
user=>
^ @joshlemerMost maps have keys that are keywords -- but you can have symbols and strings too.
(Disclaimer: i'm a newb so, school me) P = NP. or why the equals sign doesn't make sense in asking about the equality of transformational potential. We have a question of results from transformations and their equality. Computer Science is fundamentally about naming and counting. When we count the number of motions required to achieve a transformation, we are reifying certain subsequences of the transformation. Due to physical necessity, counting requires a drawer or a register in which to store a value. However, in philosophy, the question of transformation is much cleaner: Can the water that become the ice also become steam? However, it seems obvious that a robot could tie shoes so tightly and so complexly (in a complex fashion) that it would be nigh impossible to untie. However, the exact transformation that got us there is also the exact reverse transformation that can get us out. In one-way mathematical transforms over fields, the question of information entropy is alive and well, although deteriorating like swiss cheese. However, no matter how complex the tying of the shoelace, it is still a shoelace. In this way, no matter what we do to transform the data, we end up with data. Can we reintegrate data when meaning has been obscured? It's not clear if all complex transformations have more than one solution mapping, but because they all have at least one solution mapping (it has never been shown that a problem has zero solution mappings) then P must equal NP. Only if someone were able to demonstrate that there is absolutely no way to map between the two domains for a given problem could we say they are distinct sets, but to my knowledge this is yet to occur, and unlikely to be the case, even if so at first glance.
P is a set of computation problems, not a set of transformations.
The main question is can you transform each problem that lives in NP back into a P problem, my claim is yes
Well, my claim is that there is at least one way to do it for every single problem in NP. Until someone shows an NP problem that has 0 mappings to P i believe this hypothesis shall hold true, and if it holds true long enough it may be regarded as fact. P seems to be more finite than NP but I think they are both infinite fields and therefore able to accommodate one another. Anyway my main method there is proof by contradiction: if there is not zero answers then there must be >0 answers.
contradiction or induction is all we have as far as proving goes
This definitely belongs in #off-topic not in #beginners
And just like {:keys [,,,]}
you can have {:strs [,,,]}
or {:syms [,,,]}
@joshlemer
destructuring always tries to put the symbol being bound on the "left" side of the let
@joshlemer consider {{:keys [a b]} :top {c :C_IS_POORLY_NAMED} :top}
it's useful and legal to use the same value twice in hash-map values
it isn't legal to use them twice as keys - the reader rejects it
I would say the mnemonic of "key value, ..." leads you in the wrong direction - it should be "binding value, binding value, ..."
@noisesmith seems like it would be more useful to just combine those though
ahh, they can be combined, true
I vaguely recall a valid and interesting usage of the same key twice in a destructure, used in different ways, but the example is clearly escaping me (or I missed something the first time around as you point out)
ok I see so it’s that they chose to be consistent with other places bindings happen, rather than try to be consistent with how maps look. Nice!
sequential destructuring leads you into thinking about it as a pattern or template, but that's not a correct model
it's about describing structural binding
Topic change: I find transducers really cool in how they decouple the transformation from the underlying “sources”/“sinks”. But do they handle only the single-input single-output case such as collection operations, or can they encode multi-input/multi-output transformations as well, like fan-in/fan-out/routing?
generally, no
in the very special case of map
in sequence
context, the map transducer can take multiple input streams
the arities in this case fight with a lot of other uses so it's not done anywhere else
the "pull" model of how transducers are implemented means that multi-out or fan-out are not a good match (unless you are packing multiple outputs into a single output collection)
that said, core.async does have all those kinds of things and allow transducers on individual pipes (by embedding them in channels, or by using multi-threaded transducible pipelines)
Hi everybody, I am trying to get an existing project setup in InteliJ/Cursive. I created a Leiningen configuration, I am getting " Run Configuration Error: The Clojure jar is not attached to this module" . Does anybody have direction to help me out ? Any help is greatly appreciated.
I do not know the answer, but wanted to mention that if no one else here has the answer, there is a #cursive channel that might have more knowledgeable folks participating.