This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2017-03-15
Channels
- # arachne (6)
- # aws-lambda (3)
- # beginners (14)
- # boot (56)
- # cider (8)
- # cljs-dev (5)
- # cljsrn (11)
- # clojure (240)
- # clojure-dusseldorf (3)
- # clojure-greece (165)
- # clojure-italy (5)
- # clojure-romania (1)
- # clojure-russia (24)
- # clojure-uk (30)
- # clojure-ukraine (3)
- # clojurescript (29)
- # core-async (6)
- # css (1)
- # cursive (25)
- # datascript (6)
- # datomic (61)
- # dirac (1)
- # events (3)
- # hoplon (1)
- # instaparse (3)
- # jobs (4)
- # juxt (28)
- # lein-figwheel (7)
- # leiningen (19)
- # luminus (1)
- # lumo (2)
- # nyc (1)
- # off-topic (19)
- # om (25)
- # onyx (4)
- # parinfer (2)
- # pedestal (23)
- # perun (20)
- # re-frame (44)
- # reagent (20)
- # remote-jobs (3)
- # ring (3)
- # ring-swagger (5)
- # rum (12)
- # slack-help (3)
- # spacemacs (25)
- # specter (62)
- # sql (16)
- # unrepl (313)
- # yada (4)
I'm confused about how continue-then-stay
works, for example in (continue-then-stay MAP-VALS p)
from a recent example in this channeel.
I'm also a bit confused about recursive-path
, although I've used it successfully by modifying an example in the "missing piece" blog post. In (recursive-path [] p (if-path vector? [ALL p] STAY))
, what is p
bound to when it finds a vector, and why is p
put after ALL
? (Also, what's the meaning of second argument []
?) recursive-path
seems very useful, but I gather it's new since it doesn't have a docstring or other documentation yet that I've found.
Apparently I don't understand how not-selected?
works. (select [:a (not-selected? :c)] {:a 1 :b {:a 1 :b 2}})
I expected to return something since :c does not exist. "Stops navigation if the path navigator finds a result. Otherwise continues with the current structure." It couldn't have found :c, so the current structure is 1, because that's what just :a gives?
@oskarkv but :c
always navigates to something
in this case to nil
if you do (must :c)
, that only navigates if :c
exists in the map
@mars0i continue-then-stay
does literally what it says
first it navigates to the given path
then it navigates to itself
(transform (continue-then-stay STAY) inc 1)
will return 3
, because it navigates to itself, then navigates to itself again
p
in that example is bound to itself (aka the entire path definition given )
so for TREE-VALUES
, what it's saying is: if navigated at a vector, navigate to each element of the vector and recurse
otherwise (meaning not at a vector), just stay navigated at that point (finish recursing)
the []
argument i used to specify arguments to the resulting path
basically the result of recursive-path
will be a function if any arguments are provided
@oskarkv oh just noticed you were navigating to :a
first, don't think that path is what you want
Thanks @nathanmarz. That's very helpful. I'm still trying to get my head wrapped around some things that aren't intuitive for me yet. I still don't understand what p
is doing in if-path
branches in recursive-path
. Here's an example I've been using:
(def a {:a1 {:b1 {:c1 1, :c2 2}, :b2 {:c1 3, :c2 4}},
:a2 {:b1 {:c1 5, :c2 6}, :b2 {:c1 7, :c2 8}}})
(select [(recursive-path [] p (if-path map? [MAP-VALS p] [STAY]))] a)
produces [1 2 3 4 5 6 7 8]
, i.e. the leaf node values. Why do I follow MAP-VALS
with p
? Leaving out p
just produces the original map wrapped in a vector, so I know I need p
, to get the leaf nodes, but I don't understand why. Normally, if I have a path operator like MAP-VALS
in a vector, it's the first navigation operation, and then the next one is applied, and so on. Here it feels as if p
is an argument that's passed to MAP-VALS
, maybe. Is that correct? So that [MAP-VALS p]
within recursive-path
(or if-path
?) is semantically different from, a sequence of navigators immediately after select
or transform
?
no, p
is just the next navigation to do after MAP-VALS
think of it just like regular recursion
(defn foo [i]
(if (= 0 i)
1
(* 2 (foo (dec i)))))
foo
refers to itself there, just like how p
refers to the overall path
p
is (if-path map? [MAP-VALS p] [STAY]))
the effect of using p
there is to continue going to all map vals until a non-map is encountered
(btw you don't need the []
if it's just a single navigator)
the second branch of if-path
can just be STAY
are you comfortable with recursion with functions?
Ah, maybe I see. So recursive-path
doesn't in itself cause recursion to occur. It just sets up a context in which it can occur. The recursion is implemented by using the p
that it binds, in if-path
.
that's right
I see where you were confused now
recursive-path
does absolutely nothing except provide you with an object that references itself
(recursive-path [] p [ALL even?])
is the same as [ALL even?]
sort of
if you're curious, it's actually a wrapper around the lower level local-declarepath
and providepath
those two can be used to make mutually recursive paths
"sort of" yeah that's why I wrote "like" and "kind of" 🙂 . OK, I'll look at those at some point.
I'm not sure I understand continue-then-stay
followed by p
within recursive-path
, but I think I should think and experiment a bit and see if I can figure it out before asking further questions. Thanks very mush.
no problem, happy to help
Based on an answer to vikeri a week ago:
b ;=> {:b1 {:c1 1, :c2 2}, :b2 {:c1 3, :c2 4}}
(select [(recursive-path [] p
(if-path map?
(continue-then-stay MAP-VALS p)))
MAP-KEYS]
b)
;=> [:c1 :c2 :c1 :c2 :b1 :b2]
If the current element is a map, then get its vals and continue with the path, p, but also, return the current element and pass it to MAP-KEYS. So what keeps coming out of all that are the keys, and they are what are wrapped in vector. Something like that?
Or rather MAP-VALS p
causes p
into which we recurse to be bound to the outputs of MAP-VALS
. But also the entire map element at that point is passed to MAP-KEYS
.
better to think of it one step at a time
@mars0i the recursive-path
part navigates to all maps reachable via navigations to map vals
then for each map navigated to, it navigates to the keys
because of the continue-then-stay
, transformations happen first on more descendant maps
whereas with stay-then-continue
the opposite would be true
worth looking at their implementations https://github.com/nathanmarz/specter/blob/master/src/clj/com/rpl/specter.cljc#L1204
thin wrappers around multi-path