This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2021-08-25
Channels
- # anglican (2)
- # babashka (53)
- # beginners (99)
- # brompton (1)
- # calva (28)
- # circleci (43)
- # clj-commons (4)
- # clj-kondo (176)
- # cljsrn (22)
- # clojars (7)
- # clojure (175)
- # clojure-australia (2)
- # clojure-europe (20)
- # clojure-germany (1)
- # clojure-uk (5)
- # clojurescript (195)
- # cursive (18)
- # datomic (13)
- # emacs (2)
- # farolero (9)
- # find-my-lib (6)
- # fulcro (8)
- # graalvm (12)
- # gratitude (5)
- # helix (11)
- # improve-getting-started (36)
- # introduce-yourself (3)
- # jackdaw (21)
- # jobs (2)
- # joker (2)
- # malli (65)
- # meander (24)
- # nbb (2)
- # off-topic (4)
- # pathom (2)
- # polylith (17)
- # portal (5)
- # react (3)
- # reagent (22)
- # releases (1)
- # ring (4)
- # shadow-cljs (79)
- # show-and-tell (2)
- # testing (5)
- # tools-deps (9)
- # xtdb (12)
(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 => []
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)
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}))
(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]}