Liking cljdoc? Tell your friends :D

vaelii.impl.io.text

The text KB format — one file per context, one s-expression per sentence — read and written.

It is the format the shipped ontology is authored in (resources/kb/, vaelii.impl.seed), and this is where the writer for it lives, so a KB an author edited as text can be got back out of a store as text. The three formats a KB moves in are different questions and stay separate doors:

what it holdswho reads it
text (here)premises, in the author's own spelling, no handlesassert
export dump (io.export / io.import)every record and justification at its own handleimport!
the store itselfthe live KBthe engine

A dump is a KB's state; text is a KB's content. Only the second survives a re-derivation, a rename or an engine that concludes something new — which is what an author editing an ontology wants, and what a dump deliberately is not.

The format

Every form is one sentence, read with clojure.edn, so a KB file is data and can never run code. ;; comments and blank lines are free — the reader is the EDN reader, so it skips them without a line-oriented pass. The file name is the context: CxKinship.txt asserts into CxKinship, and a sentence for another context says so with (ist Cx S) as it would anywhere else. A rule carries its set/*Rule / set/defaultRule wrappers and its exceptWhen exactly as an author writes them, because that is what assert reads.

One wrapper is not part of the sentence: (set/monotonic S), the known-true class. A strength is an option on the assertion rather than part of the sentence, so there is nowhere in an s-expression for it to go, and a text KB that could not say it would round-trip a KB's monotonic premises down to defaults. It is peeled by load-entries! below into {:strength :monotonic} and never reaches the store as a functor. :default is the door's own fallback and is written as nothing, which is why no shipped file carries a wrapper.

An exceptWhen states a strength per half, because it asserts two things: the rule, and the exception qualifying it. The outer wrapper is the assertion's own option and assert gives it to both, so it can only state a class the two share; a wrapper on the query states the exception's own, and assert reads that one itself (sentex/peel-exception-strength), so a hand-written KB spells it the same way. Four pairings, four spellings:

ruleexceptionwritten as
defaultdefault(exceptWhen Q R)
defaultknown-true(exceptWhen (set/monotonic Q) R)
known-truedefault(exceptWhen Q R), and (set/monotonic R) on a line of its own
known-trueknown-true(set/monotonic (exceptWhen Q R))

The third takes two lines because there is no wrapper for weakening a half: the rule gets a line of its own at the stronger class, and mark-premise resolves a premise asserted twice to the stronger of the two.

What a text export holds, and what it does not

Premises only. A derived sentex is what the engine concluded from the premises, so writing it out would store as a premise what the KB believes as a conclusion — a reload would hold it against retraction of everything it followed from. Chaining puts it back at load, which is the whole point.

No handles. A text KB is re-asserted rather than restored, so it lands at whatever handles the loading KB mints. A caller who needs handle identity across the round trip wants export!, not this.

Deterministic. Files are named for their contexts and their forms are ordered by content (nm/by-print-key), never by handle — so two KBs holding the same knowledge export byte-identical files whatever order they were built in (docs/defenses.md, "Tie-breaks and orderings key on content").

The **text KB format** — one file per context, one s-expression per sentence — read
and written.

It is the format the shipped ontology is authored in (`resources/kb/`,
`vaelii.impl.seed`), and this is where the writer for it lives, so a KB an author
edited as text can be got back out of a store as text.  The three formats a KB moves
in are different questions and stay separate doors:

| | what it holds | who reads it |
|---|---|---|
| **text** (here) | premises, in the author's own spelling, no handles | `assert` |
| **export dump** (`io.export` / `io.import`) | every record and justification at its own handle | `import!` |
| the **store** itself | the live KB | the engine |

A dump is a KB's *state*; text is a KB's *content*.  Only the second survives a
re-derivation, a rename or an engine that concludes something new — which is what an
author editing an ontology wants, and what a dump deliberately is not.

## The format

Every form is one sentence, read with `clojure.edn`, so a KB file is data and can
never run code.  `;;` comments and blank lines are free — the reader is the EDN
reader, so it skips them without a line-oriented pass.  **The file name is the
context**: `CxKinship.txt` asserts into `CxKinship`, and a sentence for another
context says so with `(ist Cx S)` as it would anywhere else.  A rule carries its
`set/*Rule` / `set/defaultRule` wrappers and its `exceptWhen` exactly as an author
writes them, because that is what `assert` reads.

**One wrapper is not part of the sentence**: `(set/monotonic S)`, the known-true
class.  A strength is an *option* on the assertion rather than part of the sentence, so
there is nowhere in an s-expression for it to go, and a text KB that could not say it
would round-trip a KB's monotonic premises down to defaults.  It is peeled by
`load-entries!` below into `{:strength :monotonic}` and never reaches the store as a
functor.  `:default` is the door's own fallback and is written as nothing, which is why
no shipped file carries a wrapper.

**An `exceptWhen` states a strength per half**, because it asserts two things: the rule,
and the exception qualifying it.  The outer wrapper is the assertion's own option and
`assert` gives it to *both*, so it can only state a class the two share; a wrapper on
the **query** states the exception's own, and `assert` reads that one itself
(`sentex/peel-exception-strength`), so a hand-written KB spells it the same way.  Four
pairings, four spellings:

| rule | exception | written as |
|---|---|---|
| default | default | `(exceptWhen Q R)` |
| default | known-true | `(exceptWhen (set/monotonic Q) R)` |
| known-true | default | `(exceptWhen Q R)`, and `(set/monotonic R)` on a line of its own |
| known-true | known-true | `(set/monotonic (exceptWhen Q R))` |

The third takes two lines because there is no wrapper for *weakening* a half: the rule
gets a line of its own at the stronger class, and `mark-premise` resolves a premise
asserted twice to the stronger of the two.

## What a text export holds, and what it does not

**Premises only.**  A derived sentex is what the engine concluded from the premises,
so writing it out would store as a premise what the KB believes as a conclusion — a
reload would hold it against retraction of everything it followed from.  Chaining
puts it back at load, which is the whole point.

**No handles.**  A text KB is re-asserted rather than restored, so it lands at
whatever handles the loading KB mints.  A caller who needs handle identity across the
round trip wants `export!`, not this.

**Deterministic.**  Files are named for their contexts and their forms are ordered by
content (`nm/by-print-key`), never by handle — so two KBs holding the same knowledge
export byte-identical files whatever order they were built in
(docs/defenses.md, "Tie-breaks and orderings key on content").
raw docstring

context-ofclj

(context-of f)

The context a text KB file asserts into: its name without the .txt.

The context a text KB file asserts into: its name without the `.txt`.
sourceraw docstring

entriesclj

(entries source)

Every [form context] a text KB holds, with the files they came from: {:files ["CxCore.txt" …] :entries [[form context] …] :path "…"}.

source is a directory of Cx….txt files — an export-text! destination, or an ontology tree an author keeps — or a single such file. Either way the context of a form is its file's name, so a directory is read whole and handed to load-entries! in one pass rather than a file at a time: the names sort alphabetically, which is not a dependency order, and one context's content can rest on another's.

Every `[form context]` a text KB holds, with the files they came from:
`{:files ["CxCore.txt" …] :entries [[form context] …] :path "…"}`.

`source` is a **directory** of `Cx….txt` files — an `export-text!` destination, or an
ontology tree an author keeps — or a single such file.  Either way the context of a
form is its file's name, so a directory is read whole and handed to `load-entries!` in
one pass rather than a file at a time: the names sort alphabetically, which is not a
dependency order, and one context's content can rest on another's.
sourceraw docstring

kb-file?clj

(kb-file? f)

Is f a context file of a text KB directory — a regular Cx….txt? The prefix is the discriminant so a directory holding a README or a checksum is read for its KB files rather than refused for the rest.

Is `f` a context file of a text KB directory — a regular `Cx….txt`?  The prefix is
the discriminant so a directory holding a README or a checksum is read for its KB
files rather than refused for the rest.
sourceraw docstring

kb-filesclj

(kb-files dir)

The context files of the text KB directory dir, in name order.

The context files of the text KB directory `dir`, in name order.
sourceraw docstring

load-entries!clj

(load-entries! assert! entries)

Assert every [form context] of entries through assert!(assert! sentence context opts)order-insensitively: an entry refused because content further down the list has not arrived yet is retried rather than fatal. Returns how many entries were read.

assert! is passed in rather than required: this sits under vaelii.core, and the two callers above it are vaelii.core/load-text! and vaelii.impl.seed.

A KB file's order is its terms', not its dependencies' — blocks run in natural sort order, which is the whole point of grouping term-centrically — so a file cannot also be dependency-ordered. (transitiveInArg largerThan 1 partOf) sits under largerThan and (transitive partOf) under partOf, and l sorts before p. Several checks read the store (a preservation's transitivity, an arg clash, a disjointness), so without this a term-centric file is refused for where its author filed a sentence. A whole directory is one pass, for the same reason one level up: the file names sort alphabetically and a context's content can rest on another's. The context topology goes first whatever order it arrived in (topology-first), which is the one thing retrying cannot fix.

Retry rounds run while each one makes progress; the entries that survive a round that changed nothing are re-asserted without a catch, so a genuinely ill-formed one still throws — carrying the error it has once everything that could have helped it is stored, which is the error worth reporting. A list that loads clean pays one try per entry and no second round.

Assert every `[form context]` of `entries` through `assert!` —
`(assert! sentence context opts)` — **order-insensitively**: an entry refused because
content further down the list has not arrived yet is retried rather than fatal.
Returns how many entries were read.

`assert!` is passed in rather than required: this sits under `vaelii.core`, and the
two callers above it are `vaelii.core/load-text!` and `vaelii.impl.seed`.

A KB file's order is its *terms'*, not its dependencies' — blocks run in natural sort
order, which is the whole point of grouping term-centrically — so a file cannot also
be dependency-ordered.  `(transitiveInArg largerThan 1 partOf)` sits under `largerThan`
and `(transitive partOf)` under `partOf`, and `l` sorts before `p`.  Several checks
read the store (a preservation's transitivity, an `arg` clash, a disjointness), so
without this a term-centric file is refused for where its author filed a sentence.
**A whole directory is one pass**, for the same reason one level up: the file names
sort alphabetically and a context's content can rest on another's.  The **context
topology goes first** whatever order it arrived in (`topology-first`), which is the one
thing retrying cannot fix.

Retry rounds run while each one makes progress; the entries that survive a round that
changed nothing are re-asserted **without a catch**, so a genuinely ill-formed one
still throws — carrying the error it has once everything that could have helped it is
stored, which is the error worth reporting.  A list that loads clean pays one `try`
per entry and no second round.
sourceraw docstring

peel-strengthclj

(peel-strength form)

[sentence opts] for one form of a text KB file: a (set/monotonic S) wrapper becomes S with {:strength :monotonic}, and anything else is itself with nil.

The wrapper is refused rather than passed through when it is malformed — a bare (set/monotonic) or one wrapping two sentences would otherwise reach assert as a sentence whose functor is a namespace-qualified symbol, and be refused there for the wrong reason.

`[sentence opts]` for one form of a text KB file: a `(set/monotonic S)` wrapper
becomes `S` with `{:strength :monotonic}`, and anything else is itself with `nil`.

The wrapper is refused rather than passed through when it is malformed — a bare
`(set/monotonic)` or one wrapping two sentences would otherwise reach `assert` as a
sentence whose functor is a namespace-qualified symbol, and be refused there for the
wrong reason.
sourceraw docstring

read-formsclj

(read-forms source)

Every form in the text KB file source (anything io/reader takes), in file order. clojure.edn, so comments and blank lines cost nothing and no code can run.

Every form in the text KB file `source` (anything `io/reader` takes), in file order.
`clojure.edn`, so comments and blank lines cost nothing and no code can run.
sourceraw docstring

write-kb!clj

(write-kb! kb dir)
(write-kb! kb dir o)

Write kb's premises into dir as a text KB — one <Context>.txt per context — and return a summary:

{:contexts n :sentences n :skipped n :files ["CxCore.txt" …]
 :bytes n :elapsed-ms n :dir "…"}

opts narrows what is written: {:context C} for that one context's file, {:cone C} for C and every context it sees. Neither, and every context with a premise in it is written. A key this fn does not read is refused (:unknown-option) — a misspelt narrowing writes the whole KB under a summary that looks right.

dir must be absent or empty. See the namespace docstring for what a text KB holds and what it deliberately does not.

Write `kb`'s premises into `dir` as a text KB — one `<Context>.txt` per context —
and return a summary:

    {:contexts n :sentences n :skipped n :files ["CxCore.txt" …]
     :bytes n :elapsed-ms n :dir "…"}

`opts` narrows what is written: `{:context C}` for that one context's file, `{:cone C}`
for `C` and every context it sees.  Neither, and every context with a premise in it is
written.  A key this fn does not read is refused (`:unknown-option`) — a misspelt
narrowing writes the whole KB under a summary that looks right.

`dir` must be absent or empty.  See the namespace docstring for what a text KB holds
and what it deliberately does not.
sourceraw docstring

cljdoc builds & hosts documentation for Clojure/Script libraries

Keyboard shortcuts
Ctrl+kJump to recent docs
Move to previous article
Move to next article
Ctrl+/Jump to the search field
× close