Yes they should. I’m guessing they don’t?
Investigating.
OK. So those are working properly.
(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 => []
What Meander lacks is a greedy star for matching.
I know how to implement it as I have done this for zeta. For epsilon I just need a notation.
IOW Does anyone have an idea for what sort of notation we could use for a greedy version of …?
epsilon also makes the mistake of … being greedy on the RHS, something we can’t fix without, well, making a new version.
..*?
¯\_(ツ)_/¯
I'm trying to rewrite the doxa datalog parsing functions using meander, and I've pretty much stuck out on a simple thing
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
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}))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]]}
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)
So I want to correct that.
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}))
Oh. It does. I just forgot the empty case.
(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]}
🙂
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]]]]
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]}Vector queries are kind of a mixed bag. 😕
But I hope some of this helps?