Perhaps if you pre-processed the sequence to add a leading and trailing zero, then extracted all "between-zero" subsequences?
hahaha check this out:
(m/match {1 {:en "one", :de "eins", :fr "un"}
2 {:en "two", :de "zwei", :fr "deux" :es "dos"}
3 {:en "three", :de "drei", :fr "trois"}
5 {:fr "cinq"}}
{& (m/seqable [*num {& (m/seqable (m/app #(conj % *num) !lang-word-num) ...)}] ...)}
!lang-word-num)
=>
[[:en "one" 1]
[:de "eins" 1]
[:fr "un" 1]
[:en "two" 2]
[:de "zwei" 2]
[:fr "deux" 2]
[:es "dos" 2]
[:en "three" 3]
[:de "drei" 3]
[:fr "trois" 3]
[:fr "cinq" 5]]
(let [xs [1 2 3 0 4 5 6 0 7 8 0 9]]
(m/search (concat [0] xs [0])
(_ ... 0 . (m/pred (complement zero?) !part) ... 0 . _ ...)
!part))
wow, mutable variables?
yeah! if the outer variables are mutable, you can collect them with the inner rows
hmm, I've always wondered what those mutable vars could be used for
wait, they don't have to be mutable - I replaced *num with ?num and it worked fine
oh… interesting 🙂
I guess that makes sense 🙂
I thought logic vars couldn't be used inside variable-length sequences
but it seems like this is allowed because ?num
doesn't "leak" outside the pattern?
well, in this case it’s good that you can hahaha
But the final expression is pretty … ugly!!!
it could be a little cleaner if we made a thing called m/conj
as shorthand for m/app conj
…
{& (m/seqable [?num {& (m/seqable (m/conj !row ?num) ...)}] ...)}
yeah, it struck me as a little too "brain-teasery"
maybe even:
(m/map-of [?num (m/map-of (m/conj !row ?num))])
(m/into)
would be more useful than (m/conj)
and could work too
Personally I like "map-of" to behave more closely to clojure.spec
how is that?
where you have a key-pattern and val-pattern for a homogeneous map
like the one which was previously proposed
right yes, in that case map-of
won’t work here because the k/v need to be collected together
yup, just a comment about the operator name
> it could be a little cleaner if we made a thing called m/conj
as shorthand for m/app conj
…
A more general shorthand might be nice too
(m/apply f !a ?b :c)
=>
(m/app #(f %1 %2 :c) !a ?b)
Oh yeah, I like that.
{& (m/seqable [?num {& (m/seqable [?lang (m/and ?word (m/let [!row [?lang ?num ?word]]))] ...)}] ...)}
yet another way!!!
This one might work with map-of
because it doesn’t rely on key-value
pairing
ah nope: When matching, map patterns may not contain variables in their keys that would make it so there is more than one match possible.
(map-kvs ?num (map-kvs ?lang (m/and ?word (m/let [!row [?lang ?num ?word]]))))
^^ this works! 🙂where
(m/defsyntax map-kvs [ks vs]
(cond (m/match-syntax? &env)
`{& (m/seqable [~ks ~vs] ...)}
(m/subst-syntax? &env)
`{& ([~ks ~vs] ...)}
:else
&form))
similar to map-of
but different in some way I can’t describe.
Oh interestingly the ?num trick does not work inside rewrite, but *num does… I have no idea why
O.K. one last riddiculous one:
(m/match {1 {:en "one", :de "eins", :fr "un"}
2 {:en "two", :de "zwei", :fr "deux" :es "dos"}
3 {:en "three", :de "drei", :fr "trois"}
5 {:fr "cinq"}}
(map-kvs *num (map-kvs *lang (m/and *word (m/app (fn [word] (assoc-in (last !acc) [*lang *num] word)) !acc))))
(last !acc))
=>
{:en {1 "one", 2 "two", 3 "three"},
:de {1 "eins", 2 "zwei", 3 "drei"},
:fr {1 "un", 2 "deux", 3 "trois", 5 "cinq"},
:es {2 "dos"}}
I’m abusing variables to perform a reduction while parsing… conceptually though this might not be crazy if there were a way to define an accumlator variable and something a little more slick than app for updating them.
I’m thinking of something like
(map-kvs *num (map-kvs *lang *word (m/collect **acc** assoc-in [*lang *num] *word)))
o_Obut why not use just partition-by
?
> if you pre-processed the sequence to add a leading and trailing zero, then extracted all "between-zero"
Yup, but I'd call that "cheating" for the purposes of this exercise. (But that's precisely the role I was expecting the start
/`end-of-sequence` markers to play)
> but why not use just partition-by
?
We could extend that argument to the whole of meander
:)
And here's how something like Longest
would help (Mathematica - lists are {}
, ..
, ...
behave like you'd expect, :>
is just a (late) binding):
SequenceCases[list, {0..., els: Longest[Except[0]..], 0...} :> {els}]
=> {{1,2,3},{4,5,6},{7,8},{9}}
This fail[]
caught me off guard. What am I missing?
What could it be trying to match against? (`attempt` doesn't help; trace
is opaque; adding an ?a ?a
clause matches against [:a :b]
but still fails)
((m*/rewrites
(m/scan !entries)
!entries)
[:a :b])
;; => (:a :b #meander.epsilon/fail[])
NP, thanks! Would love to know what the correct result is, though!
It should be ([:a] [:b])
.
Oh, sorry, no, it should just be (:a :b)
.
So the #fail
there is the only problem.
Fixed
1🎉You could accomplish this with strategies by doing a reduction with them. But other than that I can't think of a way.
1👌I'll admit that is a bit counterintuitive. But rewrites (epsecially in strategies) is not something I've used a ton. Sadly I probably won't have time to look into it tonight but can tomorrow if no one else does.
This one is likely a bug. That fail shouldn’t be there.
1👍Also the result itself is wrong.
I’m on the road and can’t look at this until later.