Tiny Rule Engine¶
API¶
create-tre
creates a tiny rule engine
(setv tre (create-tre "Example" :debug False))
assert!
asserts a fact into a given rule engine
(assert! tre (hy is lisp))
rule
creates a new rule and inserts it into a rule engine
(rule tre (?x is lisp)
(assert! tre (?x is awesome)))
Sometimes you would want to force variable values be unique:
(rule tre (?x is on bottom of well)
(rule (?y is on bottom of well)
(unique ?x ?y)
(assert! tre (?x and ?y are on bottom of well))))
run
execute tiny rule engine until all rules and assertions are processed
(run tre)
show
show assertions associated with given symbol
(show tre 'hy)
true?
check if given assertion holds
=> (true? tre '(hy is awesome))
True
push-tre
creates a new context where to try things
=> (rule tre (?x uses flux-capacitor)
(assert! tre (?x is from future)))
=> (push-tre tre "Assuming Hy is using flux-capacitor")
=> (assert! tre (hy uses flux-capacitor))
=> (run tre)
=> (true? tre '(hy is from future))
True
frame-title
retrieves name of current frame
=> (frame-title tre)
"Assyming Hy is using flux-capacitor"
pop-tre
discards the most recent frame
=> (pop-tre tre)
=> (true? tre '(hy is from future))
False
try-in-context
is useful for creating a context and trying out a thing
inside of it, before discarding the context automatically.
=> (rule tre (?x uses Python)
(assert! tre (?x is modern system)))
=> (rule tre (?x uses Lisp)
(assert! tre (?x is timeless system)))
=> (rule tre (?x uses quantum computing)
(assert! tre (?x is future system)))
=> (try-in-context tre (hy uses quantum computing)
(print (true? '(hy is future system))))
True
=> (true? '(hy is future system))
False
Example¶
Tiny rule engine is pattern directed inference system that operates on symbols and patterns. Essentially, it deduces new assertions based on existing assertions and rules.
For example, we can deduct family relations:
First step is to initialize tiny rule engine and bind a symbol to it:
(setv tre (create-tre "family"))
Assertions (true statements) are created with assert!
. Once a truth has been
asserted, there is no way to remove it. This is because doing so would have to
remove all rules and assertions that it might have created and their results and
so on. Keeping track of web of assertions and rules would have been rather
complicated and error prone system, so it was left out.
(assert! tre (Alice is parent of Bob))
(assert! tre (Bob is parent of Charlie))
Rules are used to create new assertion and rules based on existing ones. They consist of a pattern and body. When tiny rule engine executes a rule, it processed through all assertions, checking if any of them match the pattern. When a match is found, body of the rule is executed. Special notation is used to introduce free variables in the pattern that can then be used in the body:
(rule tre (?x is parent of ?y)
(assert! tre (?y is children of ?x)))
(rule tre (?x is parent of ?y)
(rule tre (?y is parent of ?z)
(assert! tre (?x is grand-parent of ?z))))
(rule tre (?x is grand-parent of ?y)
(assert! tre (?y is grand-children of ?x)))
Final step in our example is to execute the engine and review the results, which should show that Alice indeed is grand parent of Charlie:
=> (run tre)
=> (show tre 'Alice)
Alice is parent of Bob
Alice is grand-parent of Charlie
Charlie is grand-children of Alice
Bob is children of Alice
=> (true? tre '(Alice is grand-parent of Charlie))
True
The order of adding rules and assertions into tiny rule engine doesn’t matter. Engine will keep processing rules until no further changes occur in assertions. It is even possible to run tiny rule engine in REPL, working with rules and assertions step by step.