meander

noprompt 2021-08-25T16:15:10.081100Z

Yes they should. I’m guessing they don’t?

noprompt 2021-08-25T16:22:00.081300Z

Investigating.

noprompt 2021-08-25T16:33:18.081600Z

OK. So those are working properly.

noprompt 2021-08-25T16:37:40.083300Z

(m/rewrite '[:a b c 1 2]
  [:a . (m/pred symbol? !xs) ... !rest ...]
  [!xs ... !rest ...])
;; => [b c 1 2]


(m/rewrite '[:a b c 1 2]
  [:a . (m/pred symbol? !xs) ... & ?rest]
  [!xs ... & ?rest])
;; => [b c 1 2]
rewrite is based on find. The search space for the partitions of the list after :a is.
[:a . (m/pred symbol? !xs) ... !rest ...]
;;    ^^^^^^^^ XS ^^^^^^^^    ^  YS ^
;;                             
;; XS => [],        YS => [b c 1 2]
;; XS => [b],       YS => [c 1 2]
;; XS => [b c],     YS => [1 2]
;; XS => [b c 1],   YS => [2]
;; XS => [b c 1 2], YS => []

noprompt 2021-08-25T16:38:16.083800Z

What Meander lacks is a greedy star for matching.

noprompt 2021-08-25T16:39:23.084900Z

I know how to implement it as I have done this for zeta. For epsilon I just need a notation.

noprompt 2021-08-25T16:48:22.085600Z

IOW Does anyone have an idea for what sort of notation we could use for a greedy version of ?

noprompt 2021-08-25T16:49:41.086800Z

epsilon also makes the mistake of being greedy on the RHS, something we can’t fix without, well, making a new version.

chucklehead 2021-08-25T17:41:49.087200Z

..*?

2021-08-25T18:21:03.087600Z

¯\_(ツ)_/¯

2021-08-25T19:50:16.088100Z

I'm trying to rewrite the doxa datalog parsing functions using meander, and I've pretty much stuck out on a simple thing

2021-08-25T19:54:05.089200Z

I would like to transform [:find ?e ?age :in ?name :where [?e :name ?name] [?e :age ?age]] to {:find [?e ?age] :in [?name] :where [[?e :name ?name] ...]} seems simple, but the order is not fixed, all keys are optional and all vals can be anything but a keyword

2021-08-25T19:57:18.089500Z

In theory, such a thing should work, but because & ?more is greedy, it doesn't.

(defn parse-query2 [q & args]
  (m/rewrite q
    [:find . (m/pred (complement keyword?) !find) ... & (m/cata ?more)]
    {:find [!find ...] & ?more}
    [:in . (m/pred (complement keyword?) !in) ... & (m/cata ?more)]
    {:in [!in ...] & ?more}
    [:where . (m/pred vector? !xs) ...]
    {:where [!xs ...]}

    ?x nil
    nil {:args ~args}))

noprompt 2021-08-25T22:40:30.090Z

Here’s what I came up with:

(let [q '[:find ?e ?age :in ?name :where [?e :name ?name] [?e :age ?age]]]
  (m/rewrite [q {}]
    [[(m/keyword _ _ :as ?keyword) & ?args & [(m/keyword _) & _ :as ?rest-q]] ?out]
    (m/cata [?rest-q {?keyword ?args & ?out}])

    [[(m/keyword _ _ :as ?keyword) & ?args] ?out]
    {?keyword ?args & ?out}

    [_ ?out]
    ?out))
;; =>
{:find [?e ?age],
 :in [?name],
 :where [[?e :name ?name] [?e :age ?age]]}

noprompt 2021-08-25T22:42:13.091200Z

I’m definitely not proud of the hackery here. The first rule is annoying because don’t have a greedy operator can’t

(m/and (m/not (m/keyword _)) !args)

noprompt 2021-08-25T22:42:28.091500Z

So I want to correct that.

noprompt 2021-08-25T22:45:41.091800Z

Also, ideally, something like this should work.

(let [q '[:find ?e ?age :in ?name :where [?e :name ?name] [?e :age ?age]]]
  (m/rewrite q
    [(m/keyword _ _ :as ?keyword) & ?args & (m/cata ?out)]
    {?keyword ?args & ?out}))

noprompt 2021-08-25T22:46:28.092100Z

Oh. It does. I just forgot the empty case.

noprompt 2021-08-25T22:46:30.092500Z

(let [q '[:find ?e ?age :in ?name :where [?e :name ?name] [?e :age ?age]]]
  (m/rewrite q
    [(m/keyword _ _ :as ?keyword) & ?args & (m/cata ?out)]
    {?keyword ?args & ?out}

    [] {}))
;;=>
{:where [[?e :name ?name] [?e :age ?age]],
 :in [?name],
 :find [?e ?age]}

noprompt 2021-08-25T22:48:11.093300Z

🙂

noprompt 2021-08-25T22:51:05.094700Z

I might also consider returning a sequence of pairs.

(let [q '[:find :find ?e ?age :in ?name :where [?e :name ?name] [?e :age ?age]]]
  (m/rewrite q
    [(m/keyword _ _ :as ?keyword) & ?args & (m/cata ?out)]
    [[?keyword ?args] & ?out]

    [] []))
;;=>
[[:find []]
 [:find [?e ?age]]
 [:in [?name]]
 [:where [[?e :name ?name] [?e :age ?age]]]]

noprompt 2021-08-25T22:53:33.095200Z

But growing the cata could also accommodate this.

(let [q '[:find :find ?e ?age :in ?name :where [?e :name ?name] [?e :age ?age]]]
  (m/rewrite q
    [(m/keyword _ _ :as ?keyword) . !args ...
     & (m/cata (m/or {?keyword [!args ...] & ?out} ?out))]
    {?keyword [!args ...] & ?out}

    [] {}))
;; =>
{:where [[?e :name ?name] [?e :age ?age]],
 :in [?name],
 :find [?e ?age]}

noprompt 2021-08-25T22:54:49.096Z

Vector queries are kind of a mixed bag. 😕

noprompt 2021-08-25T22:55:00.096200Z

But I hope some of this helps?