When a rule creates something new, give it a name that says where it came from.
witnesses.py · output · proof · check · try it in the playground
Suppose a rule says: every person has a record. For Alice and Bob, that means two new records exist. But what are they called? And how do we keep the record and its owner tied together?
A name for something a rule brings into existence is called a witness: it stands as evidence that the thing exists.
Can we make each witness say exactly which rule made it, and for whom — and conclude two facts about it at once?
Two people, and one rule with two conclusions:
fact(person('alice'))
fact(person('bob'))
implies(
person(Name),
has_record(Name, record('person_rule', Name)) & record_owner(record('person_rule', Name), Name),
)
The witness is the term record('person_rule', Name): a record labelled
with the rule’s name and the person it was made for.
The head holds two conclusions joined with &. Both share that same
witness, so they always talk about the same record.
has_record('alice', record('person_rule', 'alice'))
record_owner(record('person_rule', 'alice'), 'alice')
has_record('bob', record('person_rule', 'bob'))
record_owner(record('person_rule', 'bob'), 'bob')
Two facts per person. Alice’s record is record('person_rule', 'alice') —
readable, stable from run to run, and impossible to mix up with Bob’s.
peye can invent placeholder names for things a rule leaves unnamed. But an explicit witness is better when you want one per rule and per binding:
record('person_rule', 'alice') — rule 3, with
Name = ‘alice’.Bob’s two facts follow the same way from fact 2. Both conclusions cite the
same rule and the same value for Name: that is how a shared multi-part
conclusion shows up in the proof.
A separate checker read all 6 steps against the program and confirmed that:
Verdict: checked. Nothing taken on trust.
python -m peye examples/witnesses.py # the four facts
python -m peye --proof examples/witnesses.py # with their proof
Or open it in the playground.
Add fact(person('carol')) and run again: two more facts appear, with the
witness record('person_rule', 'carol').
A good name carries its own history. By building the witness from the rule and the binding, every new thing peye concludes can be traced to where it came from — even before you look at the proof.