Datalog

lib/datalog.shen evaluates relations, facts and recursive rules bottom up, to a fixed point. It is not in the image. It needs lib/native.shen, and a macro applies only to files read after it, so load them first:

\\ deps.shen
(defdatalog dependencies
  (relation imports [symbol symbol])
  (relation depends [symbol symbol])
  (relation cyclic [symbol])
  (rule (depends X Y) <-- (imports X Y))
  (rule (depends X Z) <-- (imports X Y) (depends Y Z))
  (rule (cyclic X) <-- (depends X X)))

(let Db (datalog.run dependencies [[imports a b] [imports b c] [imports x y] [imports y x]])
  (do (output "~R~%" (datalog.sorted Db depends))
      (output "~R~%" (datalog.ask Db (depends a X)))
      (output "~R~%" (datalog.sorted Db cyclic))
      (output "~A~%" (datalog.holds? Db [depends c a]))))
shen-jit eval -l lib/native.shen -l lib/datalog.shen -l deps.shen
((a b) (a c) (b c) (x x) (x y) (y x) (y y))
((a b) (a c))
((x) (y))
false
Form Meaning
(defdatalog Name Item ...) Defines a program, checked now. An item is (relation Name [Types]) or (rule Head <-- Body ...), or (rule Head) for one that always holds
(datalog.run Name Facts) A database from facts such as [imports a b]
(datalog.add Db Facts) The database with these facts added and what follows from them, changed in place and given back
(datalog.remove Db Facts) The same with these facts removed, and what no longer follows; a fact it does not have is no change
(datalog.tuples Db Relation), (datalog.sorted Db Relation) Its tuples as lists, in no particular order or sorted
(datalog.count Db Relation) How many tuples it has
(datalog.holds? Db [Relation Value ...]) Whether a tuple is there
(datalog.ask Db (Relation Term ...)) The tuples that match, in no particular order, with variables, constants and _
(datalog.define Name Items), (datalog.match Db Pattern) The same as defdatalog and datalog.ask with the program as data, where a variable is [var "X"] and _ is [any]
(datalog.plans Name), (datalog.code Name) Each rule's order of joins with no sizes to go by, and the code that gives: each kernel as written for lib/native.shen, and the KL that calls it
(datalog.stats Db) The rounds, how many plans were made, and each relation's tuples, the derivations that made them and its indexes
(datalog.run-naive Name Facts) The same result by the plain definition, slowly: what the rest is tested against
(defdatalog distances
  (relation edge [symbol symbol integer])
  (relation start [symbol])
  (relation dist [symbol integer])
  (rule (dist X 0) <-- (start X))
  (rule (dist Y D) <-- (dist X D0) (edge X Y W) (= D (+ D0 W)) (<= D 10)))
(defdatalog degrees
  (relation node [symbol])
  (relation edge [symbol symbol])
  (relation cost [symbol integer])
  (relation degree [symbol integer])
  (relation dearest [symbol integer])
  (rule (degree X N) <-- (node X) (= N (count (edge X _))))
  (rule (dearest X M) <-- (node X) (= M (max C (cost X C)))))

With nodes a and b, an edge from a to b and costs 3 and 5 for a, degree is ((a 1) (b 0)) and dearest is ((a 5)).

(defdatalog reachable
  (relation edge [symbol symbol])
  (relation start [symbol])
  (relation node [symbol])
  (relation reached [symbol])
  (relation unreached [symbol])
  (rule (reached X) <-- (start X))
  (rule (reached Y) <-- (reached X) (edge X Y))
  (rule (unreached X) <-- (node X) (not (reached X))))