This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2022-09-29
Channels
- # announcements (6)
- # babashka (23)
- # beginners (15)
- # biff (15)
- # calva (17)
- # clara (5)
- # clj-kondo (41)
- # cljdoc (2)
- # cljs-dev (67)
- # cljsrn (18)
- # clojure (19)
- # clojure-europe (25)
- # clojure-nl (2)
- # clojure-norway (9)
- # clojure-uk (2)
- # clojurescript (26)
- # core-typed (6)
- # cursive (15)
- # data-science (30)
- # datahike (1)
- # datomic (18)
- # docker (6)
- # emacs (10)
- # events (2)
- # graalvm (15)
- # graphql (5)
- # hugsql (4)
- # jobs-discuss (1)
- # joker (7)
- # lsp (36)
- # malli (28)
- # off-topic (46)
- # other-languages (1)
- # pathom (5)
- # pedestal (6)
- # polylith (5)
- # reitit (2)
- # releases (1)
- # rewrite-clj (63)
- # shadow-cljs (7)
- # spacemacs (16)
- # squint (6)
- # tools-deps (6)
- # xtdb (13)
Hi all! I was wondering how you manage the LHS complexity when you need to detect some useful path. Specifically, I will have a lot of rules that will trigger if a given "path" is detected
(defrule do-this
[ FactA (= ?id-a (:id this))
(= ?path-parameter (:some-attribute this)) ]
;; a path of facts
[ FactB (= ?id-b (:id this))]
[ FactC (= ?id-c (:id this))
(= ?id-b (:parent this))
(> 30 (:attr-x this)) ]
[ FactD (= ?id-d (:id this))
(= ?id-c (:parent this)) ]
[ FactE (= ?id-e (:id this))
(= ?id-d (:parent this)) ]
=>
(do-something)
)
Ideally, I would like something like this
(defrule do-this
[ FactA (?id-a (:id this))
(= ?path-parameter (:some-attribute this)) ]
[:test (detect-path ?path-parameter) ]
=>
(do-something)
)
Is that possible? What would be your best approach?I would be tempted to model the “path” portion as a Fact of its own, something like:
(defrecord Ancestry [ancestors key-attributes])
(defrule ancestry
[ FactB (= ?id-b (:id this))]
[ FactC (= ?id-c (:id this))
(= ?id-b (:parent this))
(> 30 (:attr-x this)) ]
[ FactD (= ?id-d (:id this))
(= ?id-c (:parent this)) ]
[ FactE (= ?id-e (:id this))
(= ?id-d (:parent this)) ]
=>
(insert! (->Ancestry {<map/tree ancestry data>} {<high level attributes from ancestors>})))
(defrule do-this
[ FactA (?id-a (:id this))
(= ?path-parameter (:some-attribute this)) ]
[Ancestry (some-logic this ?path-parameter)]
=>
(do-something))
Granted that approach works on the assumption that the ancestry is a strict set of facts B->E. If something more flexible was needed, i suppose a modification could be made:
(definterface Ancestor
(id [] "the facts id")
(parent [] "the parents id")
(attributes [] "map of attributes"))
(defrecord FactA [id some-attribute])
(defrecord FactB [record-id parent-id attr-x]
Ancestor
(id [this] record-id)
(parent [this] parent-id)
(attributes [this] {:attr-x attr-x}))
(defrecord FactC [record-id parent-id attr-y]
Ancestor
(id [this] record-id)
(parent [this] parent-id)
(attributes [this] {:attr-y attr-y}))
(defrecord FactD [record-id parent-id attr-z]
Ancestor
(id [this] record-id)
(parent [this] parent-id)
(attributes [this] {:attr-z attr-z}))
;<More Facts>
(defrecord Ancestry [id parent important-attributes])
(r/defrule progenitor
[?progenitor <- Ancestor (nil? (.parent this))]
=>
(r/insert! (->Ancestry (.id ?progenitor) nil (.attributes ?progenitor))))
(r/defrule ancestry
[?ancestor <- Ancestor
(= ?parent (.parent this))
(not= nil (.parent this))]
[?ancestry <- Ancestry
(= (.id this) ?parent)]
=>
(r/insert!
(->Ancestry
(.id ?ancestor)
(:parent ?ancestry)
(merge
(:important-attributes ?ancestry)
(.attributes ?ancestor)))))
(r/defrule do-this
[ FactA
(= ?id-a (:id this))
(= ?path-parameter (:some-attribute this)) ]
[?ancestory <- Ancestry (some-logic this ?path-parameter)]
=>
(r/insert! (->Success ?id-a ?ancestory)))
(r/defquery find-it
[]
[?q <- Success])
(defn test-session
[]
(-> (r/mk-session)
(r/insert (->FactA "1" 32))
(r/insert (->FactB "2" "3" 12))
(r/insert (->FactC "3" "4" 18))
(r/insert (->FactD "4" nil 32))
r/fire-rules
(r/query find-it)))
This assumes you own the definition of the facts, but can generate the ancestry of the facts.After writing the question I was also considering that approach (not so elaborated, though) as the best. With your response, I now feel more confident to move in that direction. Thank you, @U3KC48GHW
👍 2