(m/rewrite (range 100)
(!a !b ...)
{& [[!a !b] ...]})
;; => {0 1, 2 3, 4 5, 6 7, 8 9, 10 11, 12 13, 14 15}
!!!this looks to be the problem.. transients aren't meant to be "bashed in place"
(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}
@qythium I’m confused… what is the problem?
I would expect the output to be a 50-element map
Oh, oh, yes that is a problem.
Do you have an idea of how to fix this? zeta
already has a fix for this.
I think by using a loop/recur with the transient collection as a loop variable
Sounds good to me.
Would you like to patch it?
I learned something new about transient
s today.
I still don’t know what the hell the Clojure page on transients means by “Don’t bash in place” :man-shrugging:
I think basically it means don't treat it like a mutable collection
the conj! , assoc! etc. functions aren't like imperative statements in other languages
Yeah I just found some blog post talking about that…
Geeze… talk about a hot stove.
yeah, I made a similar mistake when first learning about transients
Okay, I changed the compile* multimethod for :rp* which fixed the above problem
Awesome.
although I have no idea what any of the internals work and how to run tests?
and there seem to be a few more uses of transient in the project
A few of those are in those pseudo rewrite rules.
Looks like :rp+
is probably busted too.
LOL and you just replace let
with loop
and it fixes it! 😂
yup, just opened a PR
Cool. Those rewrite rules can probably be toasted.
Nice work!
I’ll just take the example you gave and make that the test.
New release in just a moment…
give me a minute, rewriting :rp+ as well
ah, that was fast
I got rpm and rpl while I was in there.
rp+ too.
As I’m working on zeta
I use epsilon
from :local/root
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. 🙂
@qythium The new version should be up any moment now.
[meander/epsilon 0.0.397]
Fantastic stuff! Thanks much. 👍awesome 🙂 looking forward to zeta!
Few months 🤞
The things I’m most exited for are bit/byte/string matching, aggregation, and data generation.
I'm not sure if your changes to rp+ etc. are technically correct - still looks like in-place modification
the way I see it is, treat conj!
exactly like you would use conj
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.I have zero problems with that. 🙂
Oh I think I see what you mean.
I don't know if there is a counterexample for those cases, it might just happen to be working due to "undefined behavior"
Instead of
(conj! ,,,)
(conj! ,,,)
,,,
you’re suggesting
(conj! (conj! ,,,))
yes?yep
Got it.
pass an accumulator in a reduce
instead of (do (map... ))
Okay that just amounts to changing the map in to a reduce
Yah.
🙂
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. 👍
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"}]}
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} ...]})
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.
I think the only difference between what I posted and deleted was the use of m/gather
to grab the brands.
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. 😂
Any time!
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"}]}]}
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) ...]})
(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(also you have a typo with manifactured)
Great, will try that! Thanks again @jimmy!
And it works!
Meander is freaking awesome!