Fork me on GitHub
#meander
<
2020-03-26
>
ezmiller7701:03:28

Can anyone help me understand what the error “non exhaustive pattern match” means?

noprompt02:03:52

> Like `clojure.core/case`, if no patterns match an exception will be thrown. https://github.com/noprompt/meander/blob/epsilon/doc/operator-overview.md#match

jimmy01:03:04

It means your pattern didn't match. If you copy your data and code here we can help

qythium06:03:28

(m/rewrite [1 2 3]
  [?v ...]
  [?v ...])
Weird, this throws a "non-exhaustive pattern match" compile error

qythium07:03:18

versus the error given by m/match:

(m/match [1 2 3]
  [?v ...]
  :ok)
=>
Zero or more patterns may not have references to unbound logic variables.
   {:unbound #{?v}, :syntax-trace [(?v ...) [?v ...]]}
(which isn't that informative either)

qythium14:03:35

Huh, just realised that syntax errors like

(m/rewrite 1 ?a) 
also produce "non-exhaustive pattern match" errors instead of complaining about a missing subst-pattern argument. I don't recall it behaving like this before?

noprompt01:03:39

Hmm… yeah something seems off about that.

noprompt01:03:59

I’ll look into it.

noprompt01:03:26

I figured out the cause of the bug and will release a patch shortly. The patch will resolve both of the problems you mentioned.

grounded_sage09:03:40

What would you say is best practice for picking apart a large deeply nested json (with quite a bvit of data on the first level) transform where the end result is multiple CSV’s with id’s to relate to one another. To give context my pattern and action is a total of 138 lines in a single rewrite transform. Options layed out in front of me are. • Do a single pass with rewrite, then pass that result to some matches and searches • Do one big search where the first level data is needlessly repeated in the output.. • Do the matches and searches without using rewrite • Or do all the work in the rewrite I’m leaning towards the first or last one

grounded_sage10:03:24

Oh I just thought of a neat feature that would be nice. If not already in Meander.. haha. Use my pattern as my action. For quick inspection of the result.

jimmy15:03:21

Sadly not everything the exists on the left-hand-side works on the right-hand-side. So this would only work for something things.

jimmy15:03:57

But in zeta we actually do have ability to generate data based on a pattern. So you can actually supply a pattern and have data automatically generated for you

jimmy16:03:45

I do think we need nice inspection tools for what you’ve matched though.

grounded_sage20:03:38

Cool. Yea those things you just described sound great :)

grounded_sage10:03:28

I often copy paste my pattern to my action to see what the result is before I work on more custom outputs.

grounded_sage11:03:47

How do I go about flattening this.

(m/rewrite
   {:Sales {:Overall {:TicketCount ?sales-ticket-count
                      :Amount ?sales-amount}
            :ByCategory [{:Name !category-name
                          :TicketCount !ticket-counts
                          :Amount !amounts
                          :ByReduction [{:Name !reduction-name
                                         :TicketCount !ticket-count
                                         :Amount !amount}
                                        ..!sale-reductions]}
                         ..!sale-categories]}}
   
   {:sales-by-category [{:Name !category-name
                         :TicketCount !ticket-counts
                         :Amount !amounts
                         & [{:reduction-name !reduction-name
                             :reduction-ticket-count !ticket-count
                             :reduction-amount !amount} ..!sale-reductions]}
                        ..!sale-categories]})

grounded_sage11:03:05

Such that the result looks like this.

{:sales-by-category [{:Name "category-1"
                        :TicketCount "10"
                        :Amount "100"
                        :reduction-name "student"
                        :reduction-ticket-count "7"
                        :reduction-amount "70"}
                       {:Name "category-1"
                        :TicketCount "10"
                        :Amount "100"
                        :reduction-name "senior"
                        :reduction-ticket-count "3"
                        :reduction-amount "30"}
                       {:Name "category-2"
                        :TicketCount "20"
                        :Amount "200"
                        :reduction-name "student"
                        :reduction-ticket-count "20"
                        :reduction-amount "10"}
                       ..!sale-categories]}

jimmy16:03:55

If you can provide some input data as well I can more easily give you an example.

jimmy16:03:01

Although as I’m looking at your example it might be tricky. Not sure till I play with it.

grounded_sage16:03:22

Sorry. That’s my normal go to. Providing something that can be done at the repl.

grounded_sage16:03:17

Here is one you can plug straight into the repl.

(m/rewrite {:Sales {:Overall {:TicketCount 500
                                :Amount 20000}
                      :ByCategory [{:Name "Frontrow"
                                    :TicketCount 200
                                    :Amount 8000
                                    :ByReduction [{:Name "Student"
                                                   :TicketCount 20
                                                   :Amount 100}
                                                  {:Name "Senior"
                                                   :TicketCount 100
                                                   :Amount 289}]}
                                   {:Name "Middle"
                                    :TicketCount 240
                                    :Amount 8890
                                    :ByReduction [{:Name "Student"
                                                   :TicketCount 220
                                                   :Amount 103}
                                                  {:Name "Senior"
                                                   :TicketCount 105
                                                   :Amount 289}]}]}}
             {:Sales {:Overall {:TicketCount ?sales-ticket-count
                                :Amount ?sales-amount}
                      :ByCategory [{:Name !category-name
                                    :TicketCount !ticket-counts
                                    :Amount !amounts
                                    :ByReduction [{:Name !reduction-name
                                                   :TicketCount !ticket-count
                                                   :Amount !amount}
                                                  ..!sale-reductions]}
                                   ..!sale-categories]}}
             
             {:sales {:ticket-count ?sales-ticket-count
                      :amount ?sales-amount}
              :sales-by-category [{:Name !category-name
                                   :TicketCount !ticket-counts
                                   :Amount !amounts
                                   & [{:reduction-name !reduction-name
                                       :reduction-ticket-count !ticket-count
                                       :reduction-amount !amount}]}
                                  ..!sale-categories]})

grounded_sage16:03:20

I could also be approaching this entirely the wrong way and maybe that could be handled by doing another meander transform on a subset of the data.

jimmy18:03:58

(m/rewrite data

  {:Name ?category-name
   :TicketCount ?ticket-counts
   :Amount ?amounts
   :ByReduction [{:Name !reduction-name
                  :TicketCount !ticket-count
                  :Amount !amount}
                 ...]}

  [{:Name ?category-name
    :TicketCount ?ticket-counts
    :Amount ?amounts
    :reduction-name !reduction-name
    :reduction-ticket-count !ticket-count
    :reduction-amount !amount}
   ...]

  {:Sales {:Overall {:TicketCount ?sales-ticket-count
                     :Amount ?sales-amount}
           :ByCategory [(m/cata [!categories ...]) ...]}}
  {:sales {:ticket-count ?sales-ticket-count
           :amount ?sales-amount}
   :sales-by-category [!categories ...]})

jimmy18:03:55

I couldn't think of a way of doing this without using cata.

jimmy18:03:48

Well, of course you can break it up into multiple matches. But since you want the categories to repeat, we need them not to be in memory variables. This is a good way to do that.

noprompt18:03:30

The trick here is to use cata on each item in the :ByReduction sequence to do the rewriting of those items before dumping their contents into :sales-by-category

noprompt18:03:31

OMG I just noticed Jimmy posted the same answer. 😂

grounded_sage18:03:55

I see. So it also doesn’t matter about the order?

noprompt18:03:58

In terms of the rule ordering?

grounded_sage18:03:39

In Jimmy’s answer he put the !categories transformations above the main pattern and action. You have it after.

noprompt19:03:57

Oh, no, at least not in this case.

grounded_sage19:03:30

I figured it out after looking at it for long enough and the reference one in the docs.

grounded_sage19:03:58

I was confused as to how it determined what datastructure is the output. But it’s the one making use of the variables of course 🙂

grounded_sage19:03:04

Slowly getting there lol

noprompt19:03:55

Awesome! 🙂

jimmy19:03:21

Yeah, in this case it doesn't matter, but it could if the patterns were overlapping. Then there are tricks to differentiate them. We use some of those tricks in zeta.

grounded_sage19:03:21

Side question. What is cata short for?

jimmy20:03:10

catamorphism

jimmy20:03:56

Basically think of it like "pretend I already did recursion and match on that". That is what we are doing here.