Fork me on GitHub

+1 on group by; @jatkin how're you using m/gather? i couldn't get it to work the way i thought it would (i.e. with maps)


(m/search [{:a :whatever :b [{:n 1} {:n 2} {:n 1}]}
             {:a :goes :b [{:n 1} {:n 2} {:n 4}]}
             {:a :here :b [{:n 2} {:n 2} {:n 3}]}]
    (m/scan {:a ?a :b (m/gather {:n !n})})
    {:a ?a :n !n})
This did an ordered powerset of n

🤯 3

imho, that's a great candidate to go into the cookbook


Sure - only thing is I don't fully grok why this did what it did


haha, neither do I. i'm playing with it right now


The gather there wouldn't be necessary. On my phone but you should be able to do [pattern ...]


Yup, you are right


Gather is filter for pattern matching. Given a pattern it will go through a sequence and find all the elements that match ignoring the others.


can you elucidate on how this is different than the "normal" way? ex: [ (m/app bla) ...] or [pattern ...] also is it meant to be used with maps?


It is used on seqables. Gather is often used with pred. So you could use gather with (m/pred even?) To gather up all the even numbers. Where as doing it with ... would require everything to be an even number.


Gather has a (m/or pattern _) inside it. It does a little bit more than that though to handle more advanced repeat cases.


i think i'm missing something bc i'm still seeing it as (gather (pred even?) == syntactic sugar for [(pred even?) ...] ?


except with the latter, that form also allows for dealing with maps


Imagine the sequence were [1 2 3]. The former expression would match. The latter would not because they are not all even numbers.


Gather has nothing to do with maps. It is just matching on seqables using m/seqable


Gather is almost syntatic sugar for (seqable (or pattern _) ...)


👍 ah right right. i keep blurring when things are exhaustive matches vs. not


i think i've hit [(pred even?) ...] => not doing what i just thought it did and then replacing it with scan and changing match to find or search until something works 😛


caveat: i just recently discover m/map-of and m/submap-of which (correct me if i'm wrong) are the map equivalents for gather


Yep. That is why I came up with gather. I found myself doing the same thing and realized most of the time I wanted a simple filter.


(btw, i've added all this info to the cookbook so it'll be in a PR in a week or so)

👍 6

Oh --- and that's how I got a powerset


well, got 2 things to add now


some thoughts from weekend code sesh where i ended up rewriting a lot of meander matching: handwavy/food for thought: - cata is really powerful especially on the right hand side. - i can almost write shape morphing functions fluently which is a joy (i.e. don't need to lookup syntax and I can write it in one go) - but debugging is such a pita when i get something wrong that i found myself psychologically building stuff out much slower and more methodically. just odd irrational human behavior so only verbalizing it as food for thought - not really sure what's actionable here bc highlighting cata more upfront would probably showcase value earlier on but that's me looking at it with the "curse of knowledge" bias in that i understand the syntax enough. more concrete thoughts: - i find myself wanting to construct or extract a key out of a map alot with m/rerwrite but doing it inside of meander is frictive enough that i end up cheating and adding (let [helperfn .....])

💯 3

> i find myself wanting to construct or extract a key out of a map alot with m/rerwrite but doing it inside of meander is frictive enough that i end up cheating and adding `(let [helperfn .....]) Got an example of this? Really curious to understand more.


sure (heads up, picked this bc its more convoluted than it needs to be but is a real snippet where I just "gave up in frustration" after wrestling with it for a couple hours)


really the important bits:


i have a feeling most of these issues are a symptom of lack of "gather" for maps (cx - the submap-ofthread) And I run into it more bc i'm using rewrite and thus using meander syntax to create vs. normal clojuree


----------------- oops, forgot to add what i wanted the code to do:

;; Operator Type Decl
{:in  {:fldname {:name ?name :ctype ?ctype :initval ?dlftval } ...} 
 :out {:fldname {:name ?name :ctype ?ctype :initval ?dlftval } ...}}
;; Map of Init Values
{:fldname ?fldinitval }
;; Result =>
{:prmin  {{:prmName ?name :prmType ?ctype :prmBind (or ?fldinitval ?dlftval :prmBindNone) }}
 :prmout {{:prmName ?name :prmType ?ctype :prmBind (or ?fldinitval ?dlftval :prmBindNone)}}} 
----- highlevel: it's usually around map construction on the right hand side e.g. - merge mapA mapB - update mapA's values from mapB - variations of "cartesian/relational" operations ie canonical sql join/filter/etc


Here are at least two things you can do to make this a tad bit more percise. First you can just use get directly, rather than binding a function.

(defn oprmbinds-mk [a_arg]
  (m/rewrite a_arg
    (:makeparmbinds ?valmap [{(m/or :name :fldname) (m/and !prmn1 !prmn2 !prmn3)
                              :ctype                {:ctuid !prmctuid}} ...])

    (m/map-of !prmn1  {:prmName  !prmn2
                       :prmCtuid !prmctuid
                       :prmBind  (m/app get ?valmap !prmn3 :prmbnd-none)})))
But technically, you don’t even need the get, maps are functions themselves.
(defn oprmbinds-mk [a_arg]
  (m/rewrite a_arg
    (:makeparmbinds ?valmap [{(m/or :name :fldname) (m/and !prmn1 !prmn2 !prmn3)
                              :ctype                {:ctuid !prmctuid}} ...])

    (m/map-of !prmn1  {:prmName  !prmn2
                       :prmCtuid !prmctuid
                       :prmBind  (m/app ?valmap !prmn3 :prmbnd-none)})))
I tried doing this with rewrites, and there is definitely a way, but I still ended up using the same little app trick. As for joins and stuff, those work fairly well with search/rewrites unless you want to do things like a default value if something doesn’t exist (like you are doing here). I played with trying to make it work with an explicit join and sadly came up a bit short. Through the m/app trick above would work, I was sad I couldn’t express it more directly.
(into {}
      (m/rewrites a_arg

        (:makeparmbinds {?param ?val} 
                        (m/scan {(m/or :name :fldname) ?param 
                                 :ctype {:ctuid ?prmctuid}}))
        [?param {:prmName ?param
                 :prmCtuid ?prmctuid
                 :prmBind ?val}]))

👍 3

------------------ ah, also one more addition: i think it'd be great if there was a m/gather for maps e.g. if m/submap-of can be used with :as to capture the result of the submap filter

👍 3

At the time map-of/`submap-of` was added, the inverse of this was suggested e.g. a way to capture the part of that map that didn’t match. I think both are useful and supportable. From my point of view this is yet more support for the idea that “folds”, as I have discussed them, are primitive and relevant i.e. these two problems are symptoms of the same underlying condition which is that we do not have a way to bind with reduction. Binding, in theory sense, is a sort of reduction operation that can fail. Logic variables bind values when they are unbound and fail when an attempt is made to bind them to a logically inequivalent value. Memory and mutable variables always bind. It makes sense [to me] that reduction be exposed to allow for binding to be rich and powerful.

👍 3