This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2017-12-11
Channels
- # adventofcode (129)
- # architecture (10)
- # beginners (163)
- # boot (1)
- # cider (34)
- # cljs-dev (9)
- # clojure (210)
- # clojure-austin (11)
- # clojure-czech (2)
- # clojure-gamedev (1)
- # clojure-greece (67)
- # clojure-italy (2)
- # clojure-russia (8)
- # clojure-spec (36)
- # clojure-uk (54)
- # clojurescript (87)
- # cursive (12)
- # data-science (6)
- # datomic (13)
- # devcards (4)
- # editors (2)
- # emacs (34)
- # figwheel (6)
- # fulcro (147)
- # graphql (17)
- # lumo (54)
- # off-topic (37)
- # om (11)
- # onyx (7)
- # parinfer (10)
- # random (1)
- # re-frame (13)
- # ring (10)
- # ring-swagger (2)
- # sfcljs (1)
- # shadow-cljs (1)
- # spacemacs (32)
- # test-check (4)
- # unrepl (84)
but spec isn't a type system. we have types but we don't have a type system
hmm... maybe I'm wrong about that. It's not static typing but maybe it counts as some kind of type system.
anyway, what people are generally talking about when they talk about typesystems, and what clojure lacks even with spec, is static type checking
Yes, not a type system in the traditional sense, but given that one could def, for example, what the arguments of a function are expected to look like, it serves a similar purpose, no? Perhaps I can go about this question in another way, when experienced Clojure developers see spec, how do they anticipate incorporating it into their code? Each developer will likely have a different answer, but curious on what excites people about this in general.
newbie question: how can I assoc new items into an atom?
(swap! a assoc :k v :k2 v2 ...)
or for deeper updates (swap! a assoc-in [:k :l :m] v)
thank you @noisesmith! it was the assoc-ini I was forgetting.
I just devised a nice way to send users updates for only the thing they're looking at. by keeping track of what tag they're viewing in an atom that holds all the user-ids , the swap! is instrumental
well, more like :tag [user ids] to be clear ...
Hmmm, I want to add to a vector though, not just have one user-id per tag
append instead of overwrite scrambles to clojuredocs
then (swap! a update :tag conj uid)
but if you also remove uids from tags, it makes more sense to use a set
Tell me more about sets
(defn add-id [a tag id] (swap! a update tag (fnil conj #{}) id))
(defn remove-id [a tag id] (swap! a update tag disj id))
with sets you can call disj to remove a single element by value
oh awesome. that's exactly what I was looking for
and to check for membership, you can either use the set as a function, or use contains?
(fnil ) is new to me
seems very useful and flexible .
Clojure 1.9.0
+user=> ((fnil conj #{}) nil 1)
#{1}
+user=> ((fnil conj #{}) #{2} 1)
#{1 2}
+user=> ((fnil conj #{}) [] 1)
[1]
yes, fnil and update are a useful combination
so in the example above, is a
an (atom #{} )
it's (atom {}) - wouldn't really work the same if the atom was a set
Oh right, but each tag within it has a val that is represented by a set
the code is much simpler if the atom is a set, just (swap! a conj x)
or (swap! a disj x)
Do you think it makes more sense to create a bunch of atoms, one for each keyword I have, and use the simplified code to add/remove uids that are viewing that tag, or try and mash them all into one tag-viewers atom?
the problem with multiple atoms is it makes adding tags at runtime awkward
Ah yeah that makes sense.
if that's something you'll never need, I guess you could consider it - but I think having one item with all the tags as keys in a hashmap would be easier
Hashmap. Have yet to use one in clojure.
wait isn't a normal map in clojure a hash map?
yes - I prefer the term hashmap because we have the function map which is totally unrelated
it means the same thing
Ah, thanks for the clarification.
Yes, one atom with many tags as Keys and vectors of connected user-ids as vals
I mean on an abstract mathematical level both a hashmap and the map function describe a set of relations from one set of values to another, where each item in the first set maps to exactly one item in the second set
but that's not the level we code on, that's just a formalism 😄
Right! i am not a run-time compiler that cannot tell the difference haha
Okay I have a question. ( add-id [atom tag id) makes sense
when a user disconnects, I don't really have the pleasure of knowing which tag they were looking at, I just know they disconnected and their id
how can I get rid of every instance of their Id in the map
oh - that's trickier isn't it
you could use (swap! a #(into {} (map (fn [[k v]] [k (disj v id)])) %))
beautiful. could you give me some commentary on what that is doing?
into takes three args here - a collection {}, a transducer (map ...) and the original
it uses the transducer on each item in the original collection to generate the value to put in the result
it's very similar to calling map on the hash-map and then putting the result into a new hash-map, but unlike using map that way it doesn't need to make a lazy-seq
+user=> (into #{} (map inc) #{1 2 3 4})
#{4 3 2 5}
+user=> (into #{} (comp (map inc) (filter even?)) #{1 2 3 4})
#{4 2}
so for the line (swap! a #(into {} (map (fn [[k v]] [k (disj v id)])) %))
i can just supply id
and the rest is known
right
that's awesome and groovy.
clojure has some nice ways to work with data, once you get into the flow it can be addictive
i noticed you used (comp) in the one
yeah - it was to show how you can combine transducing functions (and subtly it shows that they compose differently than normal function application because ... reasons)
cool. that was a fairly painless introduction into transducers ^.^
Dude thanks so much
Now I just have to make sure every connected user gets a default id of some sort instead of nil
Hi, I am calling a function from a clojure library which in turn calls a java method from a java library. The problem is instead of getting the result I get a #object[.... , how I instead get the actual result? So a bit more details: In the beginning of the file I do a (:require qbits.alia.timestamp-generator :refer :all), then I run (atomic-monotonic), and I get: #object[com.datastax.driver.core.AtomicMonotonicTimestampGenerator 0x6ba19932 com.datastax.driver.core.AtomicMonotonicTimestampGenerator@6ba19932], the library function is this: https://github.com/mpenet/alia/blob/master/modules/alia/src/qbits/alia/timestamp_generator.clj#L8
@alexlykos (.next generator)
Is there do..while loop in Clojure?
do {
n *= counter--;
} while (counter > 0);
I’d use loop
… recur
for that, assuming there wasn’t a more functional alternative that eliminated the loop completely
There is while
- https://clojuredocs.org/clojure.core/while
This seems to compute something like n*(counter!), have a look at https://gist.github.com/akonring/7804273
@manutter51, @pcbalodi, @ralf Thank you!
@pcbalodi I need to do check after executing body, not before so it's not exactly while
.
There's probably a nicer, functional way of doing what you want without an explicit loop. But do-while
is an easy macro to write.
CompilerException java.lang.RuntimeException: Unable to resolve symbol: body in this context
@ghsgd2 I don’t think there are any built-in constructs, but this answer on SO suggests (https://stackoverflow.com/questions/8675911/do-while-loop-in-clojure)
(defmacro do-while
[test & body]
`(loop []
~@body
(when ~test
(recur))))
which is very similar to the actual while macro
@leonoel Useful, but I need to return result value (body)
. I'm using this hack currently:
(letfn [(body [] body-expr)]
(loop [result (body)]
(if (not condition)
result
(recur (body)))))
Is there an accepted way to handle errors from network requests in the context of an application (I don’t mean at the function level). Is it “better” to throw an exception and let it propagate up the call stack, have each function catch/throw independently, return error maps (`{:error :not-found}`) and then check them in the calling function, or something else entirely?
they are a way of life in java and you don't make a top-level scope aware of specific low-level exception types... Generally catch your exceptions as close to the source as possible and transform your exceptions to error values
Exceptions aren't huge in the clojure space like in python, but are just a fact of life because JVM
Whoops sorry I didn’t see this earlier - thanks for the response!
“Generally catch your exceptions as close to the source as possible and transform your exceptions to error values” effectively gets to the heart of what I was asking. Thank you.
To confirm, does that mean a lot of your code ends up looking something like this?
(let [result (make-api-call "/users")]
(if (:error result)
(response/bad-request)
(response/ok result)))
I would like to know more about this as well, as of now, I let all exceptions be thrown in the "inner layer" of the code (ex. code that send HTTP request, database query, etc). Leaving it to the "outer layer" to catch it (in this case a ring middleware) and compose an error response. Is there a downside to this? I've found that it makes things easier to me, as I don't have to make try catch block in each function that can throw an exception. But I'm not sure if it will ultimately become a nuisance or potentially even a problem in the future.
Have unusual issue. The same code returns correct result when run under CIDER debug but returns just []
when run without debug.
Code: https://repl.it/repls/DefensiveGlisteningFrillneckedlizard
@ghsgd2 there’s a few problems with that code, but the main issue is that for is lazy and does nothing if nothing consumes the lazy-seq it generates. When you have debugging on the debugger consumes the values for is generating, so it accidentally works.
you can fix the immediate problem by replacing for
with doseq
, it’s the same syntax but actually does the thing you want
@noisesmith Got it! Guess the other issue it's non-tail recursion which could overflow stack. But that's only the 1st version of code. Thank you very much, @noisesmith!
that’s one issue, another one is that the usage of a mutable state here is gratuitous, and that definitions in that order don’t actually compile the first time because you can’t use forward-references
also, as a minor thing, #(conj % %2)
can always be replaced with conj
where is the race?
I don’t see anywhere a second thread would be introduced
oh - the deref could happen before the swap! completes right
nevermind. i was thinking that it would immediately return the @result
without "waiting" for the other function to complete
@noisesmith
>the usage of a mutable state here is gratuitous
Going to replace with volatile
>definitions in that order don’t actually compile the first time
Yeah, will use declare
. That's because I develop mostly in REPL.
>`#(conj % %2)` can always be replaced with conj
Indeed, haven't noticed.
yeah, it always waits for swap! - there’s no way for it to go out of sync
@ghsgd2 volatile is still mutable, it’s just faster
@dpsutton there’s no such thing as a for loop, for is a comprehension, and it never uses a new thread
either the for executes and the swap! is waited for, or it doesn’t execute and there’s no swap! to wait for
well you could make it happen in another thread, but it won’t make a new thread on its own behalf
(defn flatten-1
[items result]
(for [element items]
(if (sequential? element)
(flatten-1 element result)
(do
(prn "i'm doing something")
(swap! result #(conj % %2) element)))))
but i'm conflating race and lazy and i think you already pointed this out didn't you
yes - laziness is thread safe, the error here is expecting anything lazy to happen for side effects
That's better version. But it looks like cheating because postwalk
does all heavy-lifting (and also there's postwalk
default result sequence which is ignored but still consumes memory during computation). I wonder how it's implemented but I'll keep inventing my own versions for now.
(defn flatten
[elements]
(let [result (volatile! [])]
(clojure.walk/postwalk (fn [x]
(if (not (sequential? x))
(vswap! result conj x)))
elements)
@result))
that will act weird if you have sets or hash-maps in the input
you can use tree-seq and filter to do this without mutation and avoid odd behaviors with nested non-sequential data (if you pick the right predicate on tree-seq)
@noisesmith (tree-seq branch? children root)
tree-seq
needs root. I have none.
“root” is just your input
branch? is a query that decides if you can go deeper, children turns the tree into something you can recurse on, and root is the current input
so (tree-seq sequential? seq elements)
@noisesmith It could be updated to handle sets and maps as well
(fn [x] ;; postwalk 1st arg
(if (not (or (sequential? x) (set? x) (map? x)))
(vswap! result conj x)))
And then all numbers and keys will be returned in one vector.
With your advice (maps actually are ignored but that's not an issue here):
user> (filter #(not (or (sequential? %) (set? %) (map? %))) (for [elt (tree-seq sequential? seq [1 [2 [[3]] [4 [[5]]] 6 7] 8 {:key 9} ])] elt))
(1 2 3 4 5 6 7 8)
you don’t need for here
and you can use (complement coll?) or #(not (coll? %)) as a predicate to filter
or better yet use remove coll?
@ghsgd2 the reason I say you don’t need for (for [x coll] x)
is just (seq x)
and your tree-seq is already calling seq, so you don’t need that explicitly either
which leaves us with (remove coll? (tree-seq coll? seq input))
(if you want that 9 from inside the hash-map that is)
if you don’t want the 9, (remove coll? (tree-seq sequential? seq input))
@noisesmith Impressive! 🙂 The only caveat here it's that tree-seq
uses non-tail recursion inside so it will overflow stack on big trees.
yes, everything that consumes trees including post-walk does that
for clojure built ins at least
you can move the stack usage into heap usage but you end up with slower code on the normal case, and more complex code to boot (basically using continuations on the heap instead of stack data)
@ghsgd2 also I think the fact that the self-calls are wrapped in lazy-seq means that this already happens with tree-seq, because lazy-seq lifts the continuation into a function on the heap internally
I’d need to double check that claim though
yes, checking the source - postwalk isn’t lazy, so it will overflow with large inputs, but tree-seq is creating a lazy-seq at each step so if consumed properly won’t overflow
the embedded mapcat may or may not risk a concat-bomb for very large inputs though…
Thank you very much, @noisesmith! Good to know how it works.
it always feels nice to replace many lines of mutating code with a small one liner
Is it a good idea to use clojure.zip
at all? Considering what's written in http://z.caudate.me/why-clojure-zip-sucks/
What are you trying to do with them? I think there's often abstractions built on top of them that can be used directly.
For understanding, I found the videos at https://tbaldridge.pivotshare.com/categories/zippers/1999/media really valuable to help me start figuring them out
@U054BUGT4 In this case I'm exploring what Clojure has to be prepared for upcoming tasks (I'm solving tasks at http://exercism.io).
Thank you a lot!
Personally, I wouldn't focus too much on zippers until you have a need for them (or just get the basic understanding and move on). There are pretty useful things that you can do with them though, I just haven't found it to be that common for me to need them directly.
I see. Thanks!
considering other things zacaudate has said publicly I would seek a second opinion in general
(I’m not familiar with that article though)
he said that if there's a tree [[1 2 3] []]
zipper can't put cursor into 2nd empty list to add some elements
because cursor sticks to elements
not to positions inside tree
to me zippers are an overly complicated way to do things in order to remain functional, but since clojure has mutability, we can use that instead
When dealing with very data driven basis, how does on go about understanding there options? Like, if I'm too pass a function a map, how do you know the options for that map? I guess the ideal thing is a spec or schema right?
his argument is
1. Lack of guard rails - nil punning for most movements out of the zipper as well as using :end as end.
2. Viewing the cursor as 'on an object in the tree' as opposed to 'within the tree'.
Hey there. I have a newbie question that I’d love some help with: what’s the best idiomatic way to instantiate a Java class with a default constructor, and then invoke one of its methods? I’d like to use a method from the Apache Commons Math library as the first argument to the map
function, but it’s not static, so I have to instantiate the class first. Just wondering how best to do this.
This may not be the best way but it's what I've picked up trying to answer the same question (these are from recent interop code) For functions that return a value,
(-> (ReportClientDocument.)
(.getDatabaseController))
should create a new ReportClientDocument, call the getDatabaseController function, and return the result of that method call.
To update the instance and return it,
(doto (ReportClientDocument.)
(.setReportAppServer ReportClientDocument/inprocConnectionString))
should create a ReportClientDocument, call setReportAppServer, and return the updated instance.You can also do
(def my-report (ReportClientDocument.))
or equivalent and use it from there(If I want to do this, I also have to wrap the Java method invocation in a lambda, right?)
You might also try something like:
(defn my-fn [xs]
(let [inst (Math/Whatever.)]
(map #(.method inst %1) xs)))