This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2021-09-10
Channels
- # announcements (16)
- # aws (1)
- # babashka (2)
- # beginners (33)
- # biff (2)
- # clj-kondo (13)
- # cljs-dev (1)
- # cljsrn (3)
- # clojars (6)
- # clojure (198)
- # clojure-australia (3)
- # clojure-europe (41)
- # clojure-france (3)
- # clojure-nl (2)
- # clojure-spec (7)
- # clojure-uk (12)
- # clojurescript (57)
- # clojureverse-ops (1)
- # code-reviews (3)
- # community-development (2)
- # conjure (10)
- # data-science (1)
- # datomic (15)
- # depstar (2)
- # docker (2)
- # etaoin (1)
- # events (1)
- # exercism (5)
- # fulcro (23)
- # helix (23)
- # introduce-yourself (4)
- # jobs (6)
- # kaocha (1)
- # lsp (11)
- # meander (107)
- # off-topic (8)
- # pathom (3)
- # polylith (33)
- # re-frame (23)
- # reagent (7)
- # reitit (28)
- # remote-jobs (3)
- # sci (1)
- # shadow-cljs (2)
- # specter (5)
- # sql (38)
- # tools-deps (72)
- # web-security (9)
- # xtdb (32)
(m/rewrites {:x {:y [:a :b :c]
:q [:a :b :c]}}
{!xs {!ys (m/scan :b)}}
[[!xs !ys] ...])
Is there any way to do this without using rewriteS
but with just simple rewrite
?Sorry, I'm also having trouble creating a more minimal example. I feel in over my head.
(let [r1 [[0 {:active {:a {:ids [{:business "123"}]}}}]
[1 {:active {:d {:ids [{:business "567"}]}}}]]
r2 [[0 {:active {:a {:ids [{:business "123"}]}
:b {:ids [{:business "234"}]}}}]
[1 {:active {:d {:ids [{:business "567"}]}
:c {:ids [{:business "678"}]}}}]]
f (fn [arg]
(m/rewrite arg
[[(m/and !xs !ys) {:active (m/map-of _ {:ids [{:business !ids}]})}] ...]
[[[!xs !ids] [!ys !ids] ...]]))]
(f r1) ;; [[0 "123"] [1 "567"]]
(f r2) ;; [[0 "123"] [0 "234"] [1 "567"] [1 "678"]]
)
Hey. I figured some things out. First I got the answer I wanted from this smaller example:
(let [r2 [{:a [{:word "123"}
{:word "abc"}]
:b [{:word "234"}
{:word "bcd"}]}]
f (fn [arg]
(m/find
arg
(m/gather (m/map-of _ (m/gather {:word !a})))
!a))]
(f r2))
;; => ["123" "abc" "234" "bcd"]
But it didn’t seem like I was doing this correctly since I think I should be able to search with a logic var instead of using a memory var like that.
The example for scan
gave me the idea to treat a map as a seq of MapEntry.
(m/search {:x 1 :y 2 :z 3}
(m/scan [?a ?b])
{?b ?a})
;; => ({1 :x} {2 :y} {3 :z})
So then I got this working code:
(let [r2 [{:a [{:word "123"}
{:word "abc"}]
:b [{:word "234"}
{:word "bcd"}]}]
f (fn [arg]
(m/search
arg
(m/scan (m/scan [_ (m/scan {:word ?a})]))
?a))]
(f r2))
;; => ("123" "abc" "234" "bcd")
Going back to an example of my actual problem:
(let [r2 [[0 {:active {:a {:ids [{:business "123"}
{:business "aha"}]}
:b {:ids [{:business "234"}]}}}]
[1 {:active {:d {:ids [{:business "567"}]}
:c {:ids [{:business "678"}]}}}]]
f (fn [arg]
(m/search
arg
(m/scan [?t {:active (m/scan [_ {:ids [{:business !a} ...]}])}])
[?t !a]))]
(f r2))
;; => ([0 ["123" "aha"]] [0 ["234"]] [1 ["567"]] [1 ["678"]])
I actually want to get a result like ([0 [“123” “aha” “234”]] [1 [“567" “678”]])
but I haven’t figured it out yet.
Thank you all of you for making such a sick library and for the great support.@U0BBFDED7 Thanks for the working example. I didn’t know about map-of
until I saw you use it. After that, I cloned the repo and poked around reading through some of the docstrings. Ultimately, I don’t think I want to use and
since I don’t know how many things I’ll have there; I could have made a better question than to just ask why it was broken, haha. Thanks again.
Wanted to share something cool and ask if you think I made any mistakes or it could be improved - beta reduction of tools.analyzer ast node:
(m/rewrite
node
{:op :invoke
:args [!args ..?n]
:fn {:op :fn
:methods
[{:fixed-arity ?n
:variadic? false
:form _ :arglist _ :tag _ :o-tag _ ;; rudely ignore
:params
[{:local _ :arg-id _
& !params} ...]
:body ?body}
..1]} ;; there can be only one!
& ?rest}
{:op :let
:children [:bindings :body]
:bindings
[{:init !args
:local :let
:children [:init]
& !params} ...]
:body ?body})
whereas, if these are the required things that should be there, then it's a good idea to wrap in (m/some)
Is it possible to perform a recursive search and substitution inside a bound variable?
not entirely sure this is what you’re looking for but m/cata
might help: https://github.com/noprompt/meander/blob/epsilon/doc/cookbook.md#recursion-reduction-and-aggregation
cata
still assumes I know the shape of the input (sort of). In the case where I don't want to specify all the possible patterns, is there a generic walk
?
Ben, are you able to layout in more detail what your idea/goal is? I’m not sure I totally follow.
Sure, I'm trying to implement optimization passes on tools.analyzer output. Beta reduction, copy and constant propagation
Cool. I follow this. I was looking for an example/sketch (could be contrived) of the problem and what you would like the solution to look like/the result, etc.
We do need a more general walking mechanism that isn’t strategy based. I have some ideas about that but none that I can invest time in right now.
One of the things that I’ve done in the past is write rules like this
(m/rewrite form
[::special def ?tail]
{:type :def ,,,}
((m/pred special-symbol? ?symbol) & tail)
(m/cata [::special ?symbol ?tail]))
essentially emulating a function/function call inside the system.I wanted to mention earlier, Github discussions are available too if you want to jot down something a bit more long form that lays out the full scope of the problem.
Oh nice. I was upset that slack limits the conversation history since I’d like to dig through the history for more examples.
You could probably make half a cookbook by scraping the history of this channel on the log. zulip?
Just found https://clojurians-log.clojureverse.org/meander a log of clojurians slack.
Hey. I figured some things out. First I got the answer I wanted from this smaller example:
(let [r2 [{:a [{:word "123"}
{:word "abc"}]
:b [{:word "234"}
{:word "bcd"}]}]
f (fn [arg]
(m/find
arg
(m/gather (m/map-of _ (m/gather {:word !a})))
!a))]
(f r2))
;; => ["123" "abc" "234" "bcd"]
But it didn’t seem like I was doing this correctly since I think I should be able to search with a logic var instead of using a memory var like that.
The example for scan
gave me the idea to treat a map as a seq of MapEntry.
(m/search {:x 1 :y 2 :z 3}
(m/scan [?a ?b])
{?b ?a})
;; => ({1 :x} {2 :y} {3 :z})
So then I got this working code:
(let [r2 [{:a [{:word "123"}
{:word "abc"}]
:b [{:word "234"}
{:word "bcd"}]}]
f (fn [arg]
(m/search
arg
(m/scan (m/scan [_ (m/scan {:word ?a})]))
?a))]
(f r2))
;; => ("123" "abc" "234" "bcd")
Going back to an example of my actual problem:
(let [r2 [[0 {:active {:a {:ids [{:business "123"}
{:business "aha"}]}
:b {:ids [{:business "234"}]}}}]
[1 {:active {:d {:ids [{:business "567"}]}
:c {:ids [{:business "678"}]}}}]]
f (fn [arg]
(m/search
arg
(m/scan [?t {:active (m/scan [_ {:ids [{:business !a} ...]}])}])
[?t !a]))]
(f r2))
;; => ([0 ["123" "aha"]] [0 ["234"]] [1 ["567"]] [1 ["678"]])
I actually want to get a result like ([0 [“123” “aha” “234”]] [1 [“567" “678”]])
but I haven’t figured it out yet.
Thank you all of you for making such a sick library and for the great support.I put my question in gh discussions. https://github.com/noprompt/meander/discussions/208
Ah, yeah, that can be frustrating. And I know there is a learning curve. Buuuut, hopefully, we can help. 🙂
One day I'll understand m/cata
then I'll be able to just communicate telepathically or something
It seems like the learning curve is steeper than most new things that I encounter while programming but the payoff also seems much greater than the usual new thing. So much so that the ratio of cost to benefit weighs heavily in favor of learning and using it. It’s existence and this community are also gifts so I can’t begin to be critical. I’m not actually angry; I’m just playing it up for the humor. 🙂
> the learning curve is steeper … the ratio of cost to benefit weighs heavily in favor of learning and using it
This is a perspective I think others in the channel share. Improving the overall experience and reducing the learning curve/providing help are priorities. For me, the criticism is inspiring actually, I’ve just had a rough time the past year dealing with burn out from software, and $pandemic_related_reasons
.
But I will say, this channel is awesome. I’m really proud of the folks in here. People are helpful and courteous. “No stupid questions” kind of attitude. 🙂
regarding the learning curve, I don't think there is anything that can be done about it
Is there anything I can read which would help me understand cata? Sometimes I find original papers on subjects make it click for me. Did so for HAMTs and CSP
of the non-obvious things that came out of using cata was discovering that you can put the processed data into a vector, where the first element is whatever tells you what to do with it
I understand all of these words, but have no way to translate them to actionable knowledge yet. Maybe 11pm is not the time
I would start by looking at all the examples that are in the meander repo. Reading through all the tests also gave me a lot.
I read the cata tests several times. The trivial cases made sense but didn't click for me yet. No worries, I shall bang my head against that wall until it breaks
in general I appreciate your work, e.g. on malli
, a lot can be learned by reading the code
code in meander can be fully declarative, imho it is often much more readable than pure clojure, moreover it is easy to come back to, because, omits some concepts like cata
, it is clear and understandable
for now, I'm learning meander mostly by writing doxa
and poking around in meander itself
Links here are a good starting point https://wiki.haskell.org/Performance/GHC#Looking_at_the_Core
Yes, which is why I'm not trying to understand Haskell, but the intermediate language and how they transform it for optimizations
Just found https://clojurians-log.clojureverse.org/meander a log of clojurians slack.