meander

All things about https://github.com/noprompt/meander Need help and no one responded? Feel free to ping @U5K8NTHEZ
yuhan 2020-01-05T03:51:20.250700Z

Perhaps if you pre-processed the sequence to add a leading and trailing zero, then extracted all "between-zero" subsequences?

timothypratley 2020-01-05T03:52:21.251Z

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]]

yuhan 2020-01-05T03:52:43.251200Z

(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))

yuhan 2020-01-05T03:56:37.251400Z

wow, mutable variables?

timothypratley 2020-01-05T03:57:14.251600Z

yeah! if the outer variables are mutable, you can collect them with the inner rows

yuhan 2020-01-05T04:02:41.251800Z

hmm, I've always wondered what those mutable vars could be used for

yuhan 2020-01-05T04:06:32.252Z

wait, they don't have to be mutable - I replaced *num with ?num and it worked fine

timothypratley 2020-01-05T04:08:57.252200Z

oh… interesting 🙂

timothypratley 2020-01-05T04:09:25.252400Z

I guess that makes sense 🙂

yuhan 2020-01-05T04:10:08.252600Z

I thought logic vars couldn't be used inside variable-length sequences

yuhan 2020-01-05T04:10:53.252800Z

but it seems like this is allowed because ?num doesn't "leak" outside the pattern?

timothypratley 2020-01-05T04:11:49.253Z

well, in this case it’s good that you can hahaha

timothypratley 2020-01-05T04:12:41.253200Z

But the final expression is pretty … ugly!!!

timothypratley 2020-01-05T04:14:47.253400Z

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) ...)}] ...)}

yuhan 2020-01-05T04:15:48.253700Z

yeah, it struck me as a little too "brain-teasery"

timothypratley 2020-01-05T04:16:56.253900Z

maybe even:

(m/map-of [?num (m/map-of (m/conj !row ?num))])

timothypratley 2020-01-05T04:21:29.254100Z

(m/into) would be more useful than (m/conj) and could work too

yuhan 2020-01-05T04:22:18.254300Z

Personally I like "map-of" to behave more closely to clojure.spec

timothypratley 2020-01-05T04:22:34.254500Z

how is that?

yuhan 2020-01-05T04:22:37.254700Z

where you have a key-pattern and val-pattern for a homogeneous map

yuhan 2020-01-05T04:23:23.254900Z

like the one which was previously proposed

timothypratley 2020-01-05T04:23:50.255100Z

right yes, in that case map-of won’t work here because the k/v need to be collected together

yuhan 2020-01-05T04:24:26.255300Z

yup, just a comment about the operator name

yuhan 2020-01-05T04:26:14.255500Z

> 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)

timothypratley 2020-01-05T04:26:46.255700Z

Oh yeah, I like that.

timothypratley 2020-01-05T04:40:50.255900Z

{& (m/seqable [?num {& (m/seqable [?lang (m/and ?word (m/let [!row [?lang ?num ?word]]))] ...)}] ...)}

timothypratley 2020-01-05T04:40:58.256100Z

yet another way!!!

timothypratley 2020-01-05T04:41:43.256300Z

This one might work with map-of because it doesn’t rely on key-value pairing

timothypratley 2020-01-05T04:46:00.256500Z

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.

timothypratley 2020-01-05T04:56:46.256700Z

(map-kvs ?num (map-kvs ?lang (m/and ?word (m/let [!row [?lang ?num ?word]]))))
^^ this works! 🙂

timothypratley 2020-01-05T04:56:59.256900Z

where

timothypratley 2020-01-05T04:57:03.257100Z

(m/defsyntax map-kvs [ks vs]
  (cond (m/match-syntax? &env)
        `{& (m/seqable [~ks ~vs] ...)}

        (m/subst-syntax? &env)
        `{& ([~ks ~vs] ...)}

        :else
        &form))

timothypratley 2020-01-05T04:57:28.257300Z

similar to map-of but different in some way I can’t describe.

timothypratley 2020-01-05T05:10:01.257500Z

Oh interestingly the ?num trick does not work inside rewrite, but *num does… I have no idea why

timothypratley 2020-01-05T05:39:33.257700Z

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"}}

timothypratley 2020-01-05T05:43:31.257900Z

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.

timothypratley 2020-01-05T05:50:12.258100Z

I’m thinking of something like

(map-kvs *num (map-kvs *lang *word (m/collect **acc** assoc-in [*lang *num] *word)))
o_O

mmeix 2020-01-05T14:27:09.258300Z

but why not use just partition-by?

aisamu 2020-01-05T18:36:34.266600Z

> 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 :)

aisamu 2020-01-05T18:58:08.266800Z

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}}

aisamu 2020-01-05T22:00:47.277500Z

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[])

aisamu 2020-01-06T12:20:07.282700Z

NP, thanks! Would love to know what the correct result is, though!

noprompt 2020-01-06T19:51:32.283600Z

It should be ([:a] [:b]).

noprompt 2020-01-06T19:52:25.283800Z

Oh, sorry, no, it should just be (:a :b).

noprompt 2020-01-06T19:52:44.284Z

So the #fail there is the only problem.

1👌
noprompt 2020-01-06T19:58:37.285400Z

Fixed

1🎉
jimmy 2020-01-05T22:07:17.277600Z

You could accomplish this with strategies by doing a reduction with them. But other than that I can't think of a way.

1👌
jimmy 2020-01-05T22:08:52.279400Z

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.

noprompt 2020-01-05T23:13:38.280200Z

This one is likely a bug. That fail shouldn’t be there.

1👍
noprompt 2020-01-05T23:21:14.281600Z

Also the result itself is wrong.

noprompt 2020-01-05T23:22:18.282500Z

I’m on the road and can’t look at this until later.