Why can one containment rule answer both 'what does this assembly contain?' and 'what contains this bolt?'
answer
- no arrow, just a relation
- neither position is the input
- matching binds either side
- the open position is what is searched
- goals needing bound arguments restore direction
basics
~20 sBecause a rule states a relation rather than a function. Its arguments are logical variables that unification can bind on either side, so whichever argument you leave unbound is the one the engine searches for.
solid answer
~40 sA rule head like `partOf(Whole, Part)` names a relation between two positions; neither is declared as input or output. When a query is posed, the engine **unifies** the goal with the head: a constant you supplied binds that position, and a variable you left open stays free until a fact binds it. So `partOf(gearbox, X)` searches for parts, and `partOf(W, keyway)` searches for wholes, from the same clauses. Unification is what makes this work - a symmetric match that binds variables on whichever side is open, undone again on backtracking. The two-way property is real but not unconditional: as soon as a rule body does something that requires an argument to be already bound, such as evaluating an arithmetic expression or negating a goal, that clause only works in one direction.
code
pseudocode · 13 linesfact contains("gearbox", "shaft")
fact contains("shaft", "keyway")
rule partOf(Whole, Part):
contains(Whole, Part)
rule partOf(Whole, Part):
contains(Whole, Middle)
partOf(Middle, Part)
# query partOf("gearbox", X) -> X = "shaft", then X = "keyway"
# query partOf(W, "keyway") -> W = "shaft", then W = "gearbox"
# same two clauses answer both; only the open position differsgo deeper
Remember that a rule defines a relation between positions, not a function from inputs to outputs, so leaving a different position open asks a different question of the same clauses.
Explain unification itself: a symmetric match that binds open positions on either side, undone on backtracking, which is why one definition serves several goal shapes.
Show where the two-way property breaks - goals that need bound arguments impose modes - and say how you would document which argument patterns a relation actually supports.
Consider the interface consequence: publishing a relation commits you to every goal shape callers will try, including the fully open one that enumerates everything.
## Relations, not functions The habit this question breaks is the function habit. A function has a fixed arrow: arguments in, result out, and asking it to run backwards is a different function you would have to write. A logic rule has no arrow. `partOf(Whole, Part)` is a **relation** - a set of pairs that satisfy it - and a query simply asks which members of that set match the shape you supplied. That is why a single definition answers what look like two different questions. They are the same question with different positions left open. ## What unification actually does **Unification** is the matching operation at the heart of the engine. Given two terms, it finds the most general substitution that makes them identical, or fails. Four cases cover it: 1. **A variable against a constant** - the variable is bound to that constant for the rest of the branch. 2. **Two constants** - they match if identical, otherwise the match fails and the engine backtracks. 3. **Two variables** - they are aliased, so binding either one later binds both. 4. **Two compound terms** - the names and argument counts must agree, then the arguments are unified pairwise, recursively. Two properties distinguish this from assignment, and they are what the follow-up usually probes. Unification is **symmetric**: it does not care which side of the match the variable sits on, which is precisely why the relation has no input side. And a binding is **provisional**: it lives only on the current search branch and is undone when the engine backtracks past the point that made it. Assignment is directional and destructive; unification is symmetric and reversible. ## One rule, both directions Take containment facts plus the two-clause transitive definition. Query with the first position bound and the second open, and the engine walks forward from the assembly, collecting what is inside it. Query with the second position bound and the first open, and exactly the same clauses walk the facts the other way, collecting the wholes. The clause text does not know which of its positions was supplied. | goal shape | what is bound | what the engine does | |---|---|---| | both positions constants | everything | a check: succeeds or fails, no search for values | | first bound, second open | the whole | enumerates the parts inside it | | first open, second bound | the part | enumerates the wholes containing it | | both positions open | nothing | enumerates every pair in the relation | That last row is worth naming in an interview, because it is the one that surprises people: a fully open goal is a legitimate query that streams the entire relation, and a definition that is well behaved in the other three shapes can be unusably expensive in this one. ## Where directionality comes back The two-way property is a property of **pure** relational goals, and real rules often contain goals that are not pure in this sense: - An arithmetic evaluation needs its operands known before it can produce a number, so the arguments feeding it must be bound by earlier goals. - A negated goal asks whether something is underivable, which is only a meaningful question once its subject is known. - A goal that reaches outside the knowledge base - reading, printing, calling something - has a direction by nature. Engines describe this as a clause's **modes**: which argument patterns it supports. A clause with a mode restriction is not broken; it is simply a relation you may only query one way, and calling it the other way either fails, errors, or - worst - quietly gives an answer that is not the one you meant. Part of reading someone else's logic program is working out which of its relations are genuinely two-way and which are functions in relational clothing. ## Why the mechanism outlives the paradigm Unification is not confined to programs written in a resolution-based logic language. The same operation - match two structures, bind the open positions on either side, fail on a genuine conflict - is the engine of **Hindley-Milner type inference**, which is why a compiler can work out a type you never wrote from the way a value is used, in either direction. Recognising unification when you meet it elsewhere is most of the practical value of knowing this paradigm at all. Its one-way cousin, pattern matching, binds variables on one side only: the match either fits the given value or does not, and the value is never constrained to fit the pattern.
- How does unification differ from assignment?Assignment is directional and destructive: it writes a value into a named cell and the write stays. Unification is symmetric - it binds whichever side is open so the two terms become identical - and the binding is provisional, undone as soon as the engine backtracks past the choice that created it.
- What does the engine do when both arguments of the goal are already bound?It stops being a search and becomes a check. The clauses are still tried, but every position is constrained, so the only possible outcomes are success or failure - no values are produced. This is the cheapest goal shape and a useful way to force the engine to verify rather than enumerate.
- Why does a rule that computes an arithmetic value stop working in both directions?Because evaluation is one-way: it needs its operands known before it can produce a result, so any argument feeding the expression must be bound by an earlier goal. The clause then supports only some argument patterns - its modes - and a caller who leaves the wrong position open gets an error or a wrong answer rather than a search.
A relation is a marriage register rather than a lookup function: the same entry answers 'who is she married to?' and 'who is he married to?', because the register records a pair, not a direction.
saying these in an interview costs you the question
- Says the first argument is the input and the second the output
- Claims the engine generates a reversed copy of each rule
- Describes unification as assignment into a variable
- Thinks a binding survives backtracking once it is made
- Assumes every relation is safely queryable in every direction