This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2017-06-09
Channels
- # beginners (121)
- # boot (28)
- # cider (106)
- # clara (57)
- # cljs-dev (70)
- # cljsrn (6)
- # clojure (145)
- # clojure-dev (7)
- # clojure-italy (36)
- # clojure-russia (42)
- # clojure-spec (26)
- # clojure-uk (127)
- # clojurescript (103)
- # core-async (10)
- # cursive (56)
- # datascript (66)
- # datomic (16)
- # defnpodcast (1)
- # emacs (18)
- # events (6)
- # figwheel (1)
- # jobs (1)
- # luminus (1)
- # lumo (44)
- # off-topic (58)
- # om (17)
- # onyx (2)
- # parinfer (75)
- # pedestal (4)
- # re-frame (18)
- # ring (4)
- # ring-swagger (8)
- # rum (7)
- # spacemacs (7)
- # specter (2)
- # sql (4)
- # unrepl (39)
- # untangled (17)
- # vim (3)
- # yada (21)
Well @jfntn , I used to classify I kind of link status to avoid chains of ifs, but my experience is that it was more complex than I thougth, so I changed to datascript to be more clear and simple
here is an example what I did
(defn limite [chave]
(read-string (chave (:referencia (:config sistema)))))
(defrecord IcmpLocalizacao [nome-link localidade jitter latencia perda])
(defrecord Problema [mensagem nome-link localidade])
(defrule ligacao-fragmentada
[?local <- IcmpLocalizacao (= ?nome-link nome-link) (= ?localidade localidade) (> perda (limite :perda))]
=>
(insert! (->Problema :fragmentada ?nome-link ?localidade)))
(defrule telefonia-degradada
[?local <- IcmpLocalizacao (= ?nome-link nome-link) (= ?localidade localidade) (> jitter (limite :jitter)) (> latencia (limite :latencia)) (<= perda (limite :perda))]
=>
(insert! (->Problema :degradada ?nome-link ?localidade)))
(defrule perda-qualidade
[?local <- IcmpLocalizacao (= ?nome-link nome-link) (= ?localidade localidade) (> jitter (limite :jitter)) (<= latencia (limite :latencia)) (<= perda (limite :perda))]
=>
(insert! (->Problema :qualidade ?nome-link ?localidade)))
(defrule atraso-telefonia
[?local <- IcmpLocalizacao (= ?nome-link nome-link) (= ?localidade localidade) (<= jitter (limite :jitter)) (> latencia (limite :latencia)) (<= perda (limite :perda))]
=>
(insert! (->Problema :atraso ?nome-link ?localidade)))
(defrule sem-comunicacao
[?local <- IcmpLocalizacao (= ?nome-link nome-link) (= ?localidade localidade) (= jitter -1) (= latencia -1) (= perda -1)]
=>
(insert! (->Problema :comunicacao_locais ?nome-link ?localidade)))
(defquery problemas-comunicacao []
[Problema (= ?mensagem mensagem) (= ?nome-link nome-link) (= ?localidade localidade)])
(defn gerar-fatos [fatos]
(let [regras (atom #{})]
(doseq [fato fatos]
(let [link (first (first fato))
valor (second (first fato))
localidade (:localidade valor)
icmp (:icmp valor)
jitter (:jitter icmp)
perda (:perda icmp)
latencia (:latencia icmp)]
(swap! regras conj (->IcmpLocalizacao link localidade jitter latencia perda))))
@regras))
(defn compilar-regras [fatos]
(into #{}
(-> (mk-session 'correlacao.item.regraslink)
(insert-all (gerar-fatos fatos))
(fire-rules)
(query problemas-comunicacao))))
in datascript
(defn- classificar-elemento [conn tipo op-jitter op-perda op-latencia jitter perda latencia]
(let [resultado (d/q '[:find ?localidade ?link
:in $ ?op-jitter ?op-perda ?op-latencia ?ref-jitter ?ref-perda ?ref-latencia
:where
[?e :link ?link]
[?e :localidade ?localidade]
[?e :jitter ?jitter]
[?e :perda ?perda]
[?e :latencia ?latencia]
[(?op-jitter ?jitter ?ref-jitter)]
[(?op-perda ?perda ?ref-perda)]
[(?op-latencia ?latencia ?ref-latencia)]
]
conn op-jitter op-perda op-latencia jitter perda latencia)]
(if (= #{} resultado)
[]
(resultado->set resultado tipo)
)))
I see that datascript was more flexible, but you can use any other ways to define rules for your job, like in https://github.com/threatgrid/naga or even clojure.logic
However, Clara has certainly been used in a way that creates logical “groups” and/or “hierarchies” of rules
You can have intermediary facts inserted that act as “blockers” for some rules, or have some rules not be able to be satisfied until certain facts are present
However, this isn’t done by “turning off” rules or by excluding rules from the rulebase/session created, instead it is done purely through logical relationships the rules express
Also, the “type” dispatch function used by Clara rules LHS conditions is pluggable. So you could do things with ad hoc hierarchies of Clojure
has some details on the custom “fact type” fn (and similarly the associated “ancestors” fn
Ok interesting, I guess I was wondering if it was valid to consider an approach where the app dynamically loads/unoads a different session depending on some external state machine
I think @fabrao may have had some interesting points above too. There is a chance that forward-chaining rules aren’t the best approach to certain sorts of problems
I would say it is not a good situation to have when your rules end up being of the form: A -> B; B -> C; C -> D; D -> E - when that chain starts to get really long and only one linear flow of logic
@jfntn well consider one of the compelling strengths of a Rete-based forward chaining rules impl like Clara - it stores a bunch of state to avoid re-calculation of join and non-joining constraints done in previous states of the system
if you flip from session to session, they will not share any of this state with one another. there is a chance that that is suitable for your needs. I’m just calling it out.
Also, the time to create a session is typically non-trivial if you have a fair number of rules involved. So often the pattern is to keep the sessions in memory. There will be limitations to how many rule sessions you can store in memory at a time. The size of them is mostly dependent on the number or rules and conditions involved
So I guess I was assuming you could somehow keep the facts but change the rules, not sure if that makes sense in practice
(def fsm {'Start {:init 'Ready}
'Ready {:missing-password 'Password-Error
:missing-email 'Email-Error
:submit 'Submitting}
'Password-Error {:change-password 'Ready}
'Email-Error {:change-email 'Ready}
'Submitting {:receive-success 'Success}})
I was imagining something like rules as transitions instead of keywords, and a sort of recursive definition where the Symbols on the right-hand side could be whole FSMs
Have you found that it is difficult to express the FSM sort of logic just using 1 session?
Wouldn’t you have to encode the transitions across many rules though? Maybe I just want something that will define a valid session from recursing over this tree
Perhaps this article is enough to go off to make a toy example in Clara with 1 session
I’m just trying to find the simplest solution the the problem and I’d hope there would be a nice mapping of the idea to a single session. Just to avoid the details of bouncing around between them
Or to flip that and just have the RHS produce a fact that your outer FSM uses to transition to the next step - I think that is what you said above
which basically (I believe) is a FSM sort of system that triggers Drools rules at certain stages
So I guess the idea came up there as well. I’m still just curious about whether or not a single session can’t express an FSM in the sense of the web app article though
Seems like it should be possible, but the article is only trying to represent a single FSM, and to extend that definition to a Statechart you have to imagine that each state on the right is not final but can have recursive fsm definitions.
(def app-statechart
{'Visitor
{:login
{'LoginForm
{'Start {:init 'Ready}
'Ready {:missing-password 'Password-Error
:missing-email 'Email-Error
:submit 'Submitting}
'Password-Error {:change-password 'Ready}
'Email-Error {:change-email 'Ready}
'Submitting {:receive-success 'Success}}}
:signup {... }}
'User {...}
'Admin {...}})
The key distinction is that for a given node in the tree, valid transitions at that state are the union of its and its parents’ transitions (or rules in our case), so rules that are not in this set are illegal
take a look here https://github.com/vvvvalvalval/datalog-rules
you can define many ruleset
and apply it in your context, so you can dynamic it for your needs
There is no engine there, but I’m assuming you put it on top of something like datascript
which may be find and fit the need. I think it just comes down to what you want out of it.