skip to content

In a facts-and-rules knowledge base of which component contains which, what does a rule give you that more facts cannot?

level: juniorimportance: should knowfreq 46%

answer

  1. two kinds of statement, not one
  2. one states a single instance
  3. the other states a condition
  4. answers nobody ever asserted
  5. one clause covers every chain depth

basics

~20 s

A rule is a general implication the engine applies to whatever facts exist, so it derives answers nobody stored - including containment at depths nobody enumerated. A fact states exactly one instance and generalises to nothing.

solid answer

~40 s

A fact asserts one instance of a relation: `contains(cabinet, tray)`. A rule asserts that a relation holds *whenever* some other goals hold, written with variables so it stands for every instance you could substitute into it. The rule is the leverage. One recursive `partOf` rule covers containment at every depth, so a query for everything inside an assembly stays correct after someone inserts a new sub-assembly in the middle of a chain - nothing about the rule changes and nothing derived has to be repaired. The engine works out a rule's consequences at query time rather than at insert time, which means derived answers cannot be stale relative to the facts, and the definition of what 'part of' means lives in exactly one clause you can read and audit.

code

pseudocode · 14 lines
pseudocode
fact contains("cabinet", "tray")
fact contains("tray", "bolt")

# a rule: head holds whenever the body goals hold
rule partOf(Whole, Part):
    contains(Whole, Part)

rule partOf(Whole, Part):
    contains(Whole, Middle)
    partOf(Middle, Part)

# query partOf("cabinet", X)  ->  X = "tray", then X = "bolt"
# adding contains("bolt", "thread") makes X = "thread" an answer too,
# with no edit to the rule and no work done at insert time

go deeper

for a junior

Be able to say that a fact records one specific instance of a relation and a rule states a condition under which the relation holds, and give an example of each in the same knowledge base.

for a middle

Explain that the engine derives a rule's consequences at query time, so one recursive rule covers chain depths nobody enumerated and keeps answering correctly when facts are added or removed.

for a senior

Talk about the operational side: derivation repeats work on every query, and choosing between deriving and materialising the closure is a real latency-versus-maintenance trade-off.

for a principal

Frame it as where the definition of a relation should live - one auditable clause that every consumer queries, versus derived data copied into several systems that then drift apart.

## Two kinds of statement A logic program describes a world with two kinds of statement, and the difference between them is the whole of this question. A **fact** asserts that a relation holds between specific things - `contains(cabinet, tray)`. It is unconditional, it mentions no variables, and it carries exactly one piece of information. A **rule** asserts that a relation holds *whenever* some other goals hold. It has a **head** (the relation being defined) and a **body** (the conditions), and because it is written with variables it stands for every instance you could obtain by substituting things for those variables. Both shapes are **Horn clauses**: at most one positive conclusion, any number of conditions. That restriction is not decoration - it is what keeps the engine's search tractable enough to be a programming model at all. Read a rule right to left, as an implication: *if the body holds for some binding of the variables, then the head holds for that binding.* Nothing in that reading mentions running, order, or time. ## The rule is applied, not executed When a query arrives, the engine takes the goal and looks for a clause whose head matches it. A fact ends that branch of the search. A rule replaces the goal with the goals in its body, which are then matched the same way. Consequences are never written down anywhere; they are re-derived on each query. Three consequences follow directly, and they are what an interviewer is listening for: - **Coverage you never enumerated.** A recursive rule - a component is part of a whole if it is directly contained, or contained in something that is part of that whole - answers for chains of any length the facts happen to form. - **Derived answers cannot go stale.** There is no copy to drift, because there is no copy. - **Retraction is automatic.** Remove a containment fact and every answer that leaned on it silently stops being derivable, with no invalidation step to write or forget. ## A worked reading Given `contains(cabinet, tray)`, `contains(tray, bolt)` and the two-clause definition of `partOf`, the query `partOf(cabinet, X)` yields `tray` from the direct clause and `bolt` through the recursive one. Add `contains(bolt, thread)` and the same query now also yields `thread`. No rule was edited, no derived table was refreshed, and no code ran at insert time. That last point is the one juniors most often miss: nothing happened when the fact was added. ## Why more facts do not substitute You can, of course, store the answers instead: assert every transitive pair as its own fact. That is a real engineering option, and sometimes the right one, but it is a different thing with different costs: - The depth of the chains is a property of the data, not of your schema, so the set of pairs to store is not known when you design it. - The stored closure has to be repaired on **every** insert and **every** delete, and a delete is the hard direction: you cannot simply remove the pairs that mention the deleted fact, because another chain may still support them. - The definition of the relation stops being readable in one place and becomes a property of whatever process fills the table. | | a rule (derived) | stored pairs (materialised) | |---|---|---| | Cost when data changes | none | recompute the affected closure | | Cost per query | a search | a lookup | | Can answers be stale? | no | yes, between write and repair | | New chain depth | covered automatically | needs re-derivation | | Where the definition lives | one clause | the maintenance process | ## What the leverage costs Derivation is not free. Each query pays for the search the engine performs on your behalf, and that search is invisible in the source: the rule tells you *what* is true, not how much work establishing it takes. Two failure modes follow from that. The first is cost - a rule whose goals are ordered badly can explore an enormous subtree to produce a small answer. The second is opacity - when an answer surprises you, the rule text alone does not show the path that produced it, and you need the engine's trace to see which facts were used. So the honest summary is not 'rules are better'. It is that a fact commits you to one instance and a rule commits you to a definition, and only the definition keeps answering correctly as the data you never anticipated arrives.

  • What happens to answers already derived from a rule when someone retracts a fact the rule leaned on?
    Nothing has to be undone, because nothing was stored. The next query redoes the derivation and simply fails where the support is gone. That is the other side of paying the search cost per query: derived answers can never be stale relative to the facts, but they can never be read cheaply either.
  • When would you store the derived pairs as facts instead of deriving them?
    When reads vastly outnumber writes and the query latency of a search is unacceptable. You then take on the closure maintenance yourself, and the painful direction is deletion: removing one containment fact does not invalidate every pair that mentions it, because another chain may still support the same pair.

saying these in an interview costs you the question

  • Calls a rule just a stored query given a name
  • Thinks derived answers must be inserted before they can be queried
  • Says you can simply store every transitive pair instead, ignoring updates and unknown depth
  • Reads the rule body as steps to run in order
  • Believes the engine recomputes consequences when a fact is added