genl, disjoint, partition, arg) from taxonomy.md.Working rules for adding vocabulary and knowledge to a vaelii KB, collected from Pace Heart's ontology reviews. Each principle has a short handle, used to cite it, with its full name below; genlPrinciple and specPrinciple relate a special case to the principle it specializes. Most end with an audit step to run on a vocab PR before it ships.
State knowledge in its strongest form specPrinciple: tightest parent, partition over disjoint, classify before you constrain If you're about to assert P, but Q is also true and Q implies P, assert Q instead. The weaker fact stays derivable, so nothing is lost, and the stronger one carries more.
This applies to instance facts, argument types and disjointness alike:
(disjoint A B) holds and A′ ⊂ A, don't also state (disjoint A′ B).Audit: for every line, ask whether a more specific true fact entails it.
Search everywhere before minting a term genlPrinciple: DRY Before declaring a term new, search every place a definition can live: the starter KB, every overlay and knowledge directory, setup and migration code, test fixtures (they show intent), all branches, the live KB, and the discussion history where vocabulary gets proposed. A term "not found" in one place is often defined in another.
Parent types: the tightest true one genlPrinciple: strongest form · specPrinciple: walk down, broad under thing Choose the closest existing parent, not a broad one that happens to be true. If you settle on a broad parent because nothing closer exists, say so in a comment and mark it provisional.
Name recurring meta-type combinations once
genlPrinciple: DRY
If facts keep stating (A P) plus (B P) for the same P, and neither A nor B is a genl of the other, mint the intersection of A and B and use that. Stating a combination once beats repeating two facts everywhere.
Check first: if one type is a genl of the other, stating both is a case of strongest form: drop the weaker fact. Example: CxCore has (genl instance_relation_predicate binary_predicate), so (binary_predicate P) next to (instance_relation_predicate P) is redundant, not a reason to mint an intersection.
If values want a hierarchy, they aren't individuals
Individuals take no genl. When an enumeration of individuals (ReadAccess, WriteAccess, …) starts wanting "write implies read", it was the wrong representation: make the distinctions predicates (hasWriteAccess genl hasReadAccess) or collections.
Example: with access kinds as individuals (ShellAccess, WriteAccess, AdminAccess), "admin implies write" has nowhere to live. As predicates, or as denotational functions with their corresponding predicates (see don't skip the predicate), it is a genl edge.
Beware predicate genls between differently typed args
(genl P Q) where P's args are typed more broadly than Q's can silently widen types: every P fact mints memberships Q's arg types require. Prefer a guarded rule:
(implies (and (P ?x ?y) (T1 ?x) (T2 ?y)) (Q ?x ?y))
T1 and T2 are named separately because Q's two arguments can have different types.
Example: (genl parentOf Q), where parentOf takes any animal and Q takes persons, makes every dog's parent a person. The guarded rule concludes Q only where both arguments are persons.
Comments state the meaning, not the term again specPrinciple: references in seeAlso A comment that restates the term's name adds nothing. Say what membership or the relation means, with examples, including the hard ones.
Classify before you constrain
genlPrinciple: strongest form
When you're about to assert a constraint (especially disjoint), first check whether the types are classified as tightly as the truth allows. If a missing true genl would make the constraint derive, add the genl and drop the constraint.
Example: a type X with only a social genl needs a hand-written (disjoint X Y). If X also has a true physical genl P, and (disjoint P Y) holds upstream, the disjointness derives and the hand-written line is redundant. The gap is the missing genl, not the missing constraint.
Audit: for every disjoint, arg or genlArg, walk both terms up their genl chains. An explicit constraint that a better classification entails is a smell.
One thing, one representation specPrinciple: factor out commonalities, look before you mint, state it once If the same thing is represented two ways at the vocabulary level, merge them when feasible: two encodings drift apart, get queried inconsistently, and contradict silently.
Merging is infeasible when the encodings put some dimension (time, modality, provenance) in structurally different places. Example: a Davidsonian event encoding gets time from an assertion about the event, while an n-ary predicate gets it from the context it's asserted in. Then keep both, bridge them with explicit rules, and say why in a comment.
This is about vocabulary. Instance-level duplication can be fine for a good reason, e.g. two sources asserting the same fact, kept separately for provenance.
Don't state what the KB already derives genlPrinciple: DRY If a fact follows from facts already stated (a genl implied by an intersection or a chain of genls, a disjoint implied by a partition or by two types' placements), don't state it. A stated redundancy is a second source for the same knowledge: when the facts it follows from change, it stays behind and asserts something nobody chose.
Two exceptions, each marked with a comment saying which one applies:
The same holds for comments. A comment doesn't restate a definitional assertion the KB already makes: no "the complement of X", "with Y it partitions Z" or bare member list when a partition, intersection or genl says it. The comment says what membership means, with examples, and leaves the structure to the assertions.
Audit: for every new genl, disjoint or arg, ask whether the rest of the KB already entails it. If so, drop it or mark which exception applies. For every comment, delete any clause that a definitional assertion already states.
Don't skip the predicate Whenever you define a function, also define the predicates that relate each of its arguments to its result, and write rules in terms of those predicates. Skipping them forces a syntactic commitment (terms must be represented as non-atomic terms), and the representation should be semantic and syntax-agnostic. A waiver is a named decision, not a default.
Tighten genls by walking down genlPrinciple: tightest parent To find a type's most specific genl, start at its current genl and try each direct spec: is every member of the type really a member of that spec, in the real world? If so, tighten, and recurse. Query the direct specs from the KB rather than recalling them.
Every type is a spec of thing.
Few direct specs of thing, all broad
genlPrinciple: tightest parent
Very few types should be direct specs of thing, and those should be very broad. A narrow type directly under thing usually means a missing intermediate genl, and that gap also hides disjointness (see classify before you constrain). Tighten it with walk down.
Keep a type consistent with its siblings
When ontologizing a type, check its siblings: everything it is disjoint with, and its seeAlso and termsRelated partners. Siblings should be placed at the same level and described in the same terms. An asymmetry between siblings is either a finding or a comment, never an accident.
Can disjoint be a partition?
genlPrinciple: strongest form
A special case of strongest form. For every (disjoint A B), look for a C whose members are exactly A ∪ B (plus any other pairwise-disjoint siblings). If the parts cover C, state (partition C A B …) and drop the disjoints it implies.
Include X in concept Y? Compare what's true of each side genlPrinciple: no OE calligraphy For a boundary question ("are prosthetics body parts?"), list the facts and rules true of X-with-Y and of X-without-Y. A side with nothing of its own, or only exceptions, isn't worth representing. Both sides rich usually means two concepts, often a type plus a role relation. A word naming each side is weak supporting evidence, since natural language is imprecise.
No teleology in a type's definition A type says what a thing is, not what it's for. A type defined by purpose, capacity for a role, or designer intent ("can serve as", "used for", "made to") sweeps in every idle instance. Most pacemakers are nobody's body part; most are old trash.
Audit: if a type's comment defines membership by purpose or role, make it a relation (bodyPartRoleOf ?thing ?body), put the role's rules on the relation, and type its args by what the fillers are.
Examples: a type necessarily_part_of_something is purpose in disguise. A broad body_part meaning "anything that can do the work of a body part" takes in every prosthetic; the kind plus a role relation keeps the two apart.
Beware "entity" (a discrete, countable object) It looks like a natural kind and is far slipperier. Temporal and spatial slices of a thing ("Einstein while at the patent office", "Einstein minus his left pinky toe") behave almost exactly like the thing. Don't make discreteness a type's differentia; pick one that slices and parts inherit (made, grown, alive, has mass), or say explicitly how they're treated.
Example: "discrete objects whose form came from being made" excludes a slice of a made thing. made's differentia, being shaped by an agent's action (found with differentia from near-misses), holds of a slice as of the whole.
Find a type's differentia from its complement genlPrinciple: no OE calligraphy List the members, then the near-misses: things under the same parent that aren't members. A property is the differentia only if every member has it and no near-miss does. If none survives, the type has no differentia and isn't worth reifying. The near-miss list is often a list of sibling types waiting to be named.
Hypothesized vocabulary comes with its definitional assertions
Every proposed term, even in a thought experiment, ships as a block: its metatype(s), genl, every arg, its disjoint/separating/orthogonal relations to siblings, and its comment. Where they apply, also relation properties (transitive, functional, …) and termsRelated/seeAlso. A term without its definitional block can't be evaluated yet.
Ship the right ontology over an engine quirk When the right form (an intersection, a partition, a definitional rule, removing a redundant edge) collides with an engine quirk, test fragility or extra work, ship the right form and fix the engine or the tests. Workarounds that weaken the ontology need an explicit decision. A real engine bug that would corrupt answers is surfaced, not quietly worked around.
The Davidsonian convention: the event goes in argument 1 Any relation of arity 2 or more that takes an event takes it as argument 1.
Audit: for every relation with an argument typed event (or a spec of it), the event is argument 1.
Example: (output ?event ?thing), not (productOf ?thing ?event). doneBy ?event ?doer follows the same convention.
Default + exception vs. enumeration When choosing between a default rule with exceptions and an explicit list of every known case, ask about a member that isn't listed:
These are considerations, not a gate. The more you'd expect or want the default to reach new, hypothesized and fictional members, the better a default with stated exceptions fits. Where it shouldn't reach them, enumerate the known cases and conclude nothing about new ones.
Example: metal is a solid by default, with mercury as the stated exception. A newly found, hypothesized or fictional metal should come out solid.
True and useful, not OE calligraphy specPrinciple: does it have rules?, differentia from near-misses The KB exists so an inference engine can conclude useful, true things about the world. When making a modelling choice, weigh what is useful as well as what is true: list what each option lets the engine conclude (new derivations, clash checks, persistence over time) and what it forbids. An option that is true but licenses nothing, or that defines a class almost nothing can belong to, loses to one that is true and does inference work.
References go in seeAlso/termsRelated, not comment prose
genlPrinciple: meaning, not name
A pointer to another term belongs in seeAlso (one-way) or termsRelated (a symmetric cluster), not in a comment. The comment says what the term means.
Can you improve this documentation?Edit on GitHub
cljdoc builds & hosts documentation for Clojure/Script libraries
| Ctrl+k | Jump to recent docs |
| ← | Move to previous article |
| → | Move to next article |
| Ctrl+/ | Jump to the search field |