meander

All things about https://github.com/noprompt/meander Need help and no one responded? Feel free to ping @U5K8NTHEZ
yuhan 2020-02-28T04:45:41.026900Z

(m/rewrite (range 100)
  (!a !b ...)
  {& [[!a !b] ...]})
;; => {0 1, 2 3, 4 5, 6 7, 8 9, 10 11, 12 13, 14 15}
!!!

yuhan 2020-02-28T04:57:13.029Z

this looks to be the problem.. transients aren't meant to be "bashed in place"

yuhan 2020-02-28T04:58:03.029300Z

(let [t (transient {})]
  (doseq [a (range 100)]
    (conj! t [a a]))
  (persistent! t))
;; => {0 0, 1 1, 2 2, 3 3, 4 4, 5 5, 6 6, 7 7}

noprompt 2020-02-28T05:01:17.029800Z

@qythium I’m confused… what is the problem?

yuhan 2020-02-28T05:02:33.030500Z

I would expect the output to be a 50-element map

noprompt 2020-02-28T05:03:02.031100Z

Oh, oh, yes that is a problem.

noprompt 2020-02-28T05:03:48.031800Z

Do you have an idea of how to fix this? zeta already has a fix for this.

yuhan 2020-02-28T05:05:10.032400Z

I think by using a loop/recur with the transient collection as a loop variable

noprompt 2020-02-28T05:08:38.033400Z

Sounds good to me.

noprompt 2020-02-28T05:10:08.033700Z

Would you like to patch it?

noprompt 2020-02-28T05:16:08.034200Z

I learned something new about transients today.

noprompt 2020-02-28T05:20:08.035400Z

I still don’t know what the hell the Clojure page on transients means by “Don’t bash in place” :man-shrugging:

yuhan 2020-02-28T05:20:53.036Z

I think basically it means don't treat it like a mutable collection

yuhan 2020-02-28T05:21:48.036900Z

the conj! , assoc! etc. functions aren't like imperative statements in other languages

noprompt 2020-02-28T05:22:12.037400Z

Yeah I just found some blog post talking about that…

noprompt 2020-02-28T05:22:19.037900Z

Geeze… talk about a hot stove.

yuhan 2020-02-28T05:22:50.038500Z

yeah, I made a similar mistake when first learning about transients

yuhan 2020-02-28T05:23:38.039500Z

Okay, I changed the compile* multimethod for :rp* which fixed the above problem

noprompt 2020-02-28T05:24:32.040700Z

Awesome.

yuhan 2020-02-28T05:24:45.041100Z

although I have no idea what any of the internals work and how to run tests?

yuhan 2020-02-28T05:24:57.041700Z

and there seem to be a few more uses of transient in the project

noprompt 2020-02-28T05:25:58.042400Z

A few of those are in those pseudo rewrite rules.

noprompt 2020-02-28T05:26:28.042700Z

Looks like :rp+ is probably busted too.

noprompt 2020-02-28T05:27:21.043200Z

LOL and you just replace let with loop and it fixes it! 😂

yuhan 2020-02-28T05:28:44.043400Z

yup, just opened a PR

noprompt 2020-02-28T05:28:59.043700Z

Cool. Those rewrite rules can probably be toasted.

noprompt 2020-02-28T05:29:38.043900Z

Nice work!

noprompt 2020-02-28T05:29:52.044300Z

I’ll just take the example you gave and make that the test.

noprompt 2020-02-28T05:29:59.044600Z

New release in just a moment…

yuhan 2020-02-28T05:30:33.045100Z

give me a minute, rewriting :rp+ as well

yuhan 2020-02-28T05:30:43.045300Z

ah, that was fast

noprompt 2020-02-28T05:44:38.046100Z

I got rpm and rpl while I was in there.

noprompt 2020-02-28T05:44:57.046500Z

rp+ too.

noprompt 2020-02-28T05:45:34.047300Z

As I’m working on zeta I use epsilon from :local/root

noprompt 2020-02-28T05:46:18.048200Z

So if I find bugs with epsilon (which I’m using to build zeta ) I can patch them as I come up. Lately, I’m relying more on others to help catch/fix bugs. 🙂

noprompt 2020-02-28T05:51:32.049600Z

@qythium The new version should be up any moment now.

[meander/epsilon 0.0.397]
Fantastic stuff! Thanks much. 👍

yuhan 2020-02-28T05:55:56.049800Z

awesome 🙂 looking forward to zeta!

noprompt 2020-02-28T05:57:09.050100Z

Few months 🤞

noprompt 2020-02-28T05:58:14.051400Z

The things I’m most exited for are bit/byte/string matching, aggregation, and data generation.

yuhan 2020-02-28T05:58:28.051600Z

I'm not sure if your changes to rp+ etc. are technically correct - still looks like in-place modification

yuhan 2020-02-28T06:00:53.052600Z

the way I see it is, treat conj! exactly like you would use conj

noprompt 2020-02-28T06:02:08.053600Z

Hmm…

(t/is (= (r/rewrite (range 20)
             (!a !b ...)
             {& [[!a !b] ..20]})
           {nil nil, 0 1, 4 5, 6 7, 12 13, 2 3, 14 15, 16 17, 10 11, 18 19, 8 9}))
is passing. If you’re concerned though and have doubts about the implementation, I’d be happy to merge another patch.

noprompt 2020-02-28T06:02:23.053900Z

I have zero problems with that. 🙂

noprompt 2020-02-28T06:04:05.055200Z

Oh I think I see what you mean.

yuhan 2020-02-28T06:04:17.055600Z

I don't know if there is a counterexample for those cases, it might just happen to be working due to "undefined behavior"

noprompt 2020-02-28T06:04:35.056100Z

Instead of

(conj! ,,,)
(conj! ,,,)
,,,
you’re suggesting
(conj! (conj! ,,,))
yes?

yuhan 2020-02-28T06:04:55.056300Z

yep

noprompt 2020-02-28T06:05:10.057Z

Got it.

yuhan 2020-02-28T06:05:29.057500Z

pass an accumulator in a reduce instead of (do (map... ))

noprompt 2020-02-28T06:05:40.057600Z

Okay that just amounts to changing the map in to a reduce

noprompt 2020-02-28T06:05:44.057800Z

Yah.

noprompt 2020-02-28T06:05:48.058200Z

🙂

noprompt 2020-02-28T06:07:28.059300Z

I do need to hop off here for a bit and can bang on it when I’m back which should be in a hour or so. If you wanna hack on it thats cool too. 👍

👌 1
niclasnilsson 2020-02-28T20:34:18.061200Z

Hi everyone! I’m trying to reshape a map with lists in it using meander, but haven’t found a way. Can this be done using only meander constructions?

(def data
  {:first-name "Jimi"
   :last-name "Hendrix"
   :guitars
    [{:brand "Fender"
      :model "Stratocaster"
      :year 1963}
     {:brand "Fender"
      :model "Stratocaster"
      :year 1965}
     {:brand "Gibson"
      :model "Les Paul Custom"
      :year 1955}]})

(m/search 
  data
  {:first-name ?first-name
   :last-name ?last-name
   :guitars (m/scan {:brand ?brand})}

  {:firstname ?first-name
   :surname ?last-name
   :make ?brand})

;; Result
({:firstname "Jimi", :make "Fender", :surname "Hendrix"}
 {:firstname "Jimi", :make "Fender", :surname "Hendrix"}
 {:firstname "Jimi", :make "Gibson", :surname "Hendrix"})

;; Result I would like to have. But how?
{:firstname "Jimi"
 :surname "Hendrix"
 :guitars
  [{:make "Fender"}
   {:make "Fender"}
   {:make "Gibson"}]}

jimmy 2020-02-28T20:36:31.061600Z

You can use rewrite to do this.

(m/rewrite
  data
  {:first-name ?first-name
   :last-name ?last-name
   :guitars [{:brand !brands} ...]}
  {:firstname ?first-name
   :surname ?last-name
   :guitars [{:make !brands} ...]})

jimmy 2020-02-28T20:36:56.062800Z

Search is going to give you back multiple possible results. If you just want one result match/rewrite is the thing you are looking for.

👍 1
noprompt 2020-02-28T20:38:06.063700Z

I think the only difference between what I posted and deleted was the use of m/gather to grab the brands.

👍 1
noprompt 2020-02-28T20:39:37.065200Z

This is what I love about this though… converging on an otherwise identical solution quickly instead of figuring out what functional programming combo is better than another. 😂

niclasnilsson 2020-02-28T20:43:39.066Z

Awesome, thanks @jimmy and @noprompt!

👍 1
🙌 1
noprompt 2020-02-28T20:44:56.066600Z

Any time!

niclasnilsson 2020-02-28T21:23:16.067500Z

A followup question, can the gathering be done in several “levels”?

;;;
;;; Map with lists with maps with lists.
;;; 

(def data
  {:first-name "Jimi"
   :last-name "Hendrix"
   :guitars
    [{:brand "Fender"
      :model "Stratocaster"
      :details [{:year 1963 :origin "USA"}
                {:year 1965 :origin "Mexico"}]}
     {:brand "Gibson"
      :model "Les Paul Custom"
      :details [{:year  1955 :origin "USA"}]}]})

(m/rewrite
  data
  {:first-name ?first-name
   :last-name ?last-name
   :guitars [{:brand !brands 
              :model !models 
              :details
              [{:year !years
                :origin !origin} 
               ...]}
             ...]}

  {:firstname ?first-name
   :surname ?last-name
   :guitars [{:make !brands 
              :model !models 
              :manifactured
              [{:year !years
                :country !origin}
               ...]}
             ...]})


;; What I get

{:firstname "Jimi",
 :surname "Hendrix"
 :guitars [{:make "Fender",
            :model "Stratocaster"}],
            :manifactured [{:country "USA", :year 1963}
                           {:country "Mexico", :year 1965}
                           {:country "USA", :year 1955}],}

;; What I'm aiming for

{:firstname "Jimi"
 :surname "Hendrix"
 :guitars
  [{:make "Fender"
    :model "Stratocaster"
    :manifactured [{:year 1963 :country "USA"}
                   {:year 1965 :country "Mexico"}]}
   {:brand "Gibson"
    :model "Les Paul Custom"
    :manifactured [{:year  1955 :origin "USA"}]}]}

niclasnilsson 2020-02-28T21:46:30.068400Z

I managed to solve it using (m/app). Is this the best/ideomatic way or is there a smarter/cleaner way?

(def data
  {:first-name "Jimi"
   :last-name "Hendrix"
   :guitars
    [{:brand "Fender"
      :model "Stratocaster"
      :details [{:year 1963 :origin "USA"}
                {:year 1965 :origin "Mexico"}]}
     {:brand "Gibson"
      :model "Les Paul Custom"
      :details [{:year  1955 :origin "USA"}]}]})

(defn rewrite-guitar-details [guitar-details]
  (m/rewrite 
    guitar-details
    {:year ?year
     :origin ?origin}

    {:year ?year
     :country ?origin}))

(defn rewrite-guitar [guitar]
  (m/rewrite 
    guitar
    {:brand ?brand
     :model ?model
     :details [!details ...]}

    {:brand ?brand
     :model ?model
     :details [(m/app rewrite-guitar-details !details) ...]}))

(m/rewrite
  data
  {:first-name ?first-name
   :last-name ?last-name
   :guitars [!guitars ...]} 

  {:firstname ?first-name
   :surname ?last-name
   :guitars [(m/app rewrite-guitar !guitars) ...]})

jimmy 2020-02-28T21:53:44.069800Z

(m/rewrite
  data
  {:first-name ?first-name
   :last-name ?last-name
   :guitars [{:brand !brands 
              :model !models 
              :details
              [{:year !years
                :origin !origin} 
               ..!n]}
             ..!m]}
  {:firstname ?first-name
   :surname ?last-name
   :guitars [{:make !brands 
              :model !models 
              :manifactured
              [{:year !years
                :country !origin}
               ..!n]}
             ..!m]})
By default ... in substitution is going to put out all values. You can control how many it does by using ..!n or ..?n. https://cljdoc.org/d/meander/epsilon/0.0.397/doc/operator-overview#repeating-with-varxiables

jimmy 2020-02-28T21:54:02.070100Z

@niclasnilsson

jimmy 2020-02-28T21:55:11.070600Z

(also you have a typo with manifactured)

niclasnilsson 2020-02-28T21:57:19.071100Z

Great, will try that! Thanks again @jimmy!

niclasnilsson 2020-02-28T21:58:51.071900Z

And it works!

niclasnilsson 2020-02-28T21:58:54.072100Z

Meander is freaking awesome!

❤️ 1
🙂 1
🎉 1