This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2018-05-15
Channels
- # aws (4)
- # beginners (98)
- # boot (23)
- # cider (63)
- # cljsrn (3)
- # clojure (259)
- # clojure-boston (1)
- # clojure-dev (2)
- # clojure-italy (6)
- # clojure-nl (17)
- # clojure-russia (1)
- # clojure-serbia (1)
- # clojure-spec (36)
- # clojure-uk (74)
- # clojurescript (11)
- # cursive (2)
- # datascript (12)
- # datomic (36)
- # defnpodcast (1)
- # devops (1)
- # docs (1)
- # emacs (15)
- # euroclojure (3)
- # fulcro (13)
- # graphql (1)
- # juxt (2)
- # lumo (27)
- # off-topic (46)
- # onyx (23)
- # pedestal (6)
- # planck (2)
- # portkey (27)
- # re-frame (18)
- # reagent (12)
- # remote-jobs (2)
- # ring-swagger (11)
- # rum (4)
- # shadow-cljs (104)
- # spacemacs (4)
- # sql (3)
- # tools-deps (5)
- # vim (45)
I am trying to write a macro that prints out maximum useful information. Right now it uses pr-str
, which is what I want for most cljs structures. But for javascript objects, sometimes I get an error like “Uncaught TypeError: Cannot convert a Symbol value to a string”. If I use str
instead, I just get [object Object]
. So I think I need to use JSON.stringify
to get something useful. Is there a predicate to figure out if something is safe to pass to pr-str
? I feel like I’ve seen some kind of protocol that you can test for but I can’t find it.
You can also extend the PrintWriter to any types that cause trouble. eg
;; Don't crash when printing JS symbols:
;; see
(extend-protocol IPrintWithWriter
js/Symbol
(-pr-writer [sym writer _]
(-write writer (str "\"" (.toString sym) "\""))))
@lee.justin.m Why not (try (pr-str x) (catch ? _ (JSON.stringify x)))
(sorry, I don't know what JS-speak for Throwable
is)
Sometimes, it's more work to figure out if something is valid than it is to just try
it and catch
the failure...
Is there a better way of updating an inner sequence of a sequence, when using transducers. I'm trying this - which gives the results I need, but I'm not sure if I'm missing a trick
(let [xform (map (fn [m] (update m :a (fn [coll] (into [] (map #(update % :b inc)) coll)))))]
(sequence xform
[{:a [{:b 1 :c 2}]}
{:a [{:b 1 :c 2} {:b 2 :c 3}]}
{:a [{:b 1 :c 2} {:b 3 :c 4}]}
{:a [{:b 1 :c 2} {:b 4 :c 5}]}]))
({:a [{:b 2, :c 2}]}
{:a [{:b 2, :c 2} {:b 3, :c 3}]}
{:a [{:b 2, :c 2} {:b 4, :c 4}]}
{:a [{:b 2, :c 2} {:b 5, :c 5}]})
@danieleneal did you consider specter
?
Hey, I’m new to ClojureScript and I’m researching the ecosystem a bit. I’m looking for a nice SPA development setup with hot reloading etc, but I’m a bit overwhelmed by the options… Can anyone give me some hints? Which tools do you use (leiningen, shadow-cljs, boot, cljsbuild etc.) and which libs do you use for rendering and state management (re-frame, om, reagent, rum, citrus etc.)?
fulcro is also worth giving a try: http://fulcro.fulcrologic.com. it has a template, guidebook, examples, and videos.
@samuel.nystedt if you're new to avoid getting overwhelmed, you can start with a template and then look at swapping things out when you need to. Try perhaps the re-frame-template
- there's a lot of info out there about how to build SPAs with reframe so it's a good place to start https://github.com/Day8/re-frame-template
lein new re-frame <project-name>
then lein figwheel dev
to kick off the figwheel server
Thanks @danieleneal, seems re-frame is popular right now. I’ll play around with the template project 🙂
🙂 I've heard good things about reframe-10x (a debugging tool) so if it's just a trial project, you could include that in the template options
lein new reframe <project-name> +10x
being able to inspect what is going on is one of the big plus points of re-frame's data driven approach
@grierson Take a look at clojure.spec.test.alpha/summarize-results
which takes the output of st/check
and produces a more amenable data structure for clojure.test
stuff...
@samuel.nystedt if you think you will use more than one or two libraries (e.g. react libraries) from npm, I’d give strong advice to use shadow-cljs for your build. It will save you a tremendous amount of headache.
I'm working on a challenge problem where I'm giving a big glob of deeply nested JSON, and need to sum all of the numbers in it (none of which are represented as string).
I was able to parse the JSON no problem using cheshire, and I can easily print all of the numbers using clojure.walk.postwalk #(if (number? %) (prn %)) data)
. I know that I can use atoms to sum all of the numbers by introducing side-effects, but I was wondering if there was a more idiomatic (pure) way to do this?
misread
Cool, I'll look into tree-seq
!
My current solution is:
(def *sum (atom 0))
(walk/postwalk
#(if (number? %) (swap! *sum + %))
data)
with tree-seq you don't need mutation, just filter and apply +
reduce is better imo
I was always wondering about this — what are the implications between (apply + args)
vs (reduce + args)
? Is the vararg version of +
slower ?
It actually depends some on what args is but for me conceptually it makes more sense to walk down a series of numbers, summing as we go rather than invoking + once on a giant coll of numbers - Clojure’s function invocation machinery falls into a special case when for >20 args that is less efficient.
(->> data tree-seq (filter number?) (reduce +))
(reduce + (tree-seq data))
gives an arity error
I'm trying to figure out how to actually call tree-seq
what’s the json structure?
or rather, what does data look like?
Deeply nested, irregular
top-level is a key
oh, I forgot tree-seq has a bunch of options
does (tree-seq coll? seq data)
work to give you data?
It does though it's still nested
(->> data (tree-seq coll? seq data) (filter number?) (reduce +))
Calling flatten on that looks better, but still not quite there
(->> data (tree-seq coll? seq) (filter number?) (reduce +))
works!
cooool
drop the last reduce if you want to verify all the numbers are there
it's the correct answer
So how does seq
work here?
I'm a bit confused about that argument position in the tree-seq
func
just gives you the sequence of children for a node
like a map, a vector, a map entry
Okay; I thought that root
had to be a value, not a function
the doc is a bit confusing to me
the first arg to tree-seq is a fn for “is this a branching node?“. the second arg is a fn for “give me the children for this branching node”
the third arg is the root
oooh, wait, I get it, misread the arg order
thanks! that helps
if you ever look at clojure.zip, zippers are defined in a similar way
but with an additional function to tell the zipper how to construct a new branching node
Interestingly, my original solution using mutation is about twice as fast, at least with this data size.
(def *sum (atom 0))
(time (do
(walk/postwalk
#(if (number? %) (swap! *sum + %))
data)
(prn @*sum)))
(time (->> data (tree-seq coll? seq) (filter number?) (reduce +) prn))
Not to say that it's that important, but my general assumption with clojure is that mutation is slower outside of transients; I don't have much experience to back that on though
building the whole tree, doing a filter and then summing everything must be slower than just doing +
on a number every time you encounter a number
yeah, you’re building a couple layers of lazy seq
@montanonic specter’s got you covered: (reduce + 0 (traverse (walker number?) your-thing))
That looks real nice
Better how?
less overhead due to transducers, but unless you have a giant dataset it probably won’t make that big of a difference
Oh wow
after JIT compilation @schmee's solutions are both 2-3x faster than the mutation one
at least in this scenario
What's the best way to learn it? its docs?
:thumbsup:
note that walker
is one of the slower navigators, if you implement a custom recursive-path
tuned to your data structure you could probably at least double the speed
Thanks for your feedback everyone. This was really helpful and edifying!
so there’s no reason you can’t make a tree-reducible like tree-seq…
(defn tree-red
[branch? children root]
(reify clojure.lang.IReduceInit
(reduce [_ f val]
(loop [acc val
[node & nodes] [root]]
(if node
(recur (f acc node) (if (branch? node) (concat(children node) nodes) nodes))
acc)))))
and then you can just reduce over the tree
(transduce (filter number?) + 0 (tree-red coll? seq data))
if you want depth-first like tree-seq, I’m not sure you can do that
I’ll leave that to you for homework… :)
yeah, actually, come to think of it, I was just talking about depth first searches and tail recursion in the irc channel the other day
you have to do cps to turn the calls in to tail calls, which the contract for reduce doesn't let you do
When I execute clj -Sdeps '{:deps {tools.deps.alpha {:mvn/version "0.5.435"}}}'
It report error:
Error building classpath. Could not find artifact tools.deps.alpha:tools.deps.alpha:jar:0.5.435 in central ( )
org.eclipse.aether.resolution.ArtifactResolutionException: Could not find artifact tools.deps.alpha:tools.deps.alpha:jar:0.5.435 in central ( )
But I confirm this version artifact exist http://search.maven.org/#search%7Cgav%7C1%7Cg:%22org.clojure%22AND%20a:%22tools.deps.alpha%22Is there anyone knows how to solve this problem?
It’s org.clojure/tools.deps.alpha
Aha, that's it. Thanks. @alexmiller
After clj -Sdeps '{:deps {org.clojure/tools.deps.alpha {:mvn/version "0.5.435"}}}'
. Then execute user=> (use 'clojure.tools.deps.alpha)
namespace clojure.tools.deps.alpha.repl
does not exist, but can't found function (add-lib ...)
. I followed the steps on http://insideclojure.org/2018/05/04/add-lib/
That’s an experimental feature - it’s only on a branch
The command line to try it is in the article
It uses tools.deps as a git dep to pull from an explicit commit (on the branch)
There will likely be changes before it makes its way into a release