factgraph
| Kind | kit |
|---|---|
| Categories | data-structures domain-specific |
| Keywords | knowledge-graph facts rules validation data-modeling |
Knowledge graph for modeling facts, rules, and calculations in Kit
Files
| File | Description |
|---|---|
.editorconfig | Editor formatting configuration |
.gitignore | Git ignore rules for build artifacts and dependencies |
.tool-versions | asdf tool versions (Zig, Kit) |
LICENSE | MIT license file |
README.md | This file |
examples/basic.kit | Basic usage example |
examples/fact-graph.kit | Example: fact graph |
kit.toml | Package manifest with metadata and dependencies |
src/main.kit | Main module |
tests/factgraph.test.kit | Tests for factgraph |
Dependencies
No Kit package dependencies.
Installation
kit add gitlab.com/kit-lang/packages/kit-factgraph.gitUsage
import Kit.Factgraph as FactGraph
main = fn =>
# Create a dictionary with metadata, type definitions, and fact definitions
dict = FactGraph.empty-dictionary {name: "Person Schema", version: "1.0"}
|> FactGraph.add-type "PositiveInt" (FactGraph.make-type "PositiveInt" "Int")
|> FactGraph.add-fact "/person/name" (FactGraph.make-fact "String")
|> FactGraph.add-fact "/person/age" (FactGraph.make-fact "PositiveInt")
|> FactGraph.add-fact "/person/email" (FactGraph.make-optional-fact "String")
# Create an empty fact graph from the dictionary
graph = FactGraph.empty dict
|> FactGraph.set "/person/name" "Alice"
|> FactGraph.set "/person/age" 30
# Read facts by path
name = FactGraph.get graph "/person/name"
age = FactGraph.get graph "/person/age"
println "Name: ${name}"
println "Age: ${age}"
# Inspect paths and serialize the graph data
println "All paths: ${FactGraph.paths graph}"
println "Data: ${FactGraph.to-map graph}"
mainDeveloper Notes
kit-factgraph models data with three related structures:
- A dictionary created with
FactGraph.empty-dictionary, then extended with type, fact, and calculation definitions. - A graph created with
FactGraph.empty, which stores dictionary metadata, graph data, and validation errors. - Path-based data access with slash-delimited paths such as
/person/age.
Useful exported operations include:
| Operation | Purpose |
|---|---|
empty-dictionary | Create a dictionary with caller-defined metadata |
make-type / add-type | Define named fact types |
make-fact / make-optional-fact / add-fact | Define required and optional facts |
add-calculation / is-calculated? | Register and inspect derived facts |
split-path | Split /a/b/c style paths into path segments |
get / set | Read and write graph values by path |
get-at-path / set-at-path | Read and write nested Map values directly |
paths | Collect paths currently present in graph data |
dictionary / data / has-errors? / get-errors | Inspect graph internals |
to-map / from-map | Convert graph data to and from plain maps |
is-valid-type? / is-valid-fact? | Validate built-in and dictionary-backed fact types |
Built-in validation recognizes Int, Integer, Float, String, Bool, and Boolean. Unknown type names currently pass validation so callers can layer domain-specific validation on top.
Some tests for nested writes and complex dictionary inserts are currently commented with TODOs for an OutOfMemory issue in recursive Map.insert usage. Keep this in mind when changing set-at-path, add-type, add-fact, or add-calculation.
Development
Running Examples
Run the basic example with the interpreter:
kit run examples/basic.kitRun the larger fact graph demonstration:
kit run examples/fact-graph.kitCompile examples to a native binary:
kit build examples/basic.kit && ./basicRunning Tests
Run the test suite:
kit testRun the factgraph test file directly:
kit test tests/factgraph.test.kitRun the test suite with coverage:
kit test --coverageRunning kit dev
Run the standard development workflow (format, check, test):
kit devThis will:
- Format and check source files in
src/ - Run tests in
tests/with coverage
Generating Documentation
Generate API documentation from doc comments:
kit docNote: Kit sources with doc comments (##) will generate HTML documents in docs/*.html.
Cleaning Build Artifacts
Remove generated files, caches, and build artifacts:
kit task cleanNote: Defined in kit.toml.
Local Installation
To install this package locally for development:
kit installThis installs the package to ~/.kit/packages/@kit/factgraph/, making it available for import as Kit.Factgraph in other projects.
License
This package is released under the MIT License - see LICENSE for details.
Exported Functions & Types
empty-dictionary
Create an empty fact dictionary with metadata
a -> {meta: a, types: Map, facts: Map, calcs: Map}
dict = FactGraph.empty-dictionary {name: "Tax Form", version: "1.0"}empty
Create an empty fact graph with a dictionary
a -> {dict: a, data: Map, errors: List}
graph = FactGraph.empty dictmake-type
Create a type definition
NonEmptyString -> NonEmptyString -> TypeDef
int-type = FactGraph.make-type "PositiveInt" "Int"add-type
Add a type definition to a dictionary
{meta: a, types: Map, facts: Map, calcs: Map} -> NonEmptyString -> TypeDef -> {meta: a, types: Map, facts: Map, calcs: Map}
dict = dict |> FactGraph.add-type "Money" (FactGraph.make-type "Money" "Float")make-fact
Create a required fact definition
String -> FactDef
age-fact = FactGraph.make-fact "Int"make-optional-fact
Create an optional fact
String -> FactDef
status-fact = FactGraph.make-optional-fact "String"add-fact
Add a fact definition to a dictionary
{meta: a, types: Map, facts: Map, calcs: Map} -> NonEmptyString -> FactDef -> {meta: a, types: Map, facts: Map, calcs: Map}
dict = dict |> FactGraph.add-fact "/person/age" age-factadd-calculation
Add a calculation (derived fact) to a dictionary
{meta: a, types: Map, facts: Map, calcs: Map} -> NonEmptyString -> (b -> c) -> {meta: a, types: Map, facts: Map, calcs: Map}
dict = dict |> FactGraph.add-calculation "/total" (fn(graph) => ...)is-calculated?
Check if a path is a calculated fact
{calcs: Map, ..} -> NonEmptyString -> Bool
is-calc = FactGraph.is-calculated? dict "/total"split-path
Split a path like "/person/age" into parts ["person", "age"]
String -> List String
parts = FactGraph.split-path "/person/age"
# parts = ["person", "age"]get
Get a value from the fact graph at the given path
{data: Map, ..} -> NonEmptyString -> a
age = FactGraph.get graph "/person/age"set
Set a value in the fact graph at the given path
{dict: a, data: Map, errors: List} -> NonEmptyString -> b -> {dict: a, data: Map, errors: List}
graph = FactGraph.set graph "/person/age" 30get-at-path
Get a value at a nested path in a map
Map String a -> NonEmptyString -> a
set-at-path
Set a value at a nested path in a map
Map String a -> NonEmptyString -> a -> Map String a
paths
Get all paths in the fact graph data
{data: Map, ..} -> List String
all-paths = FactGraph.paths graphdictionary
Get the dictionary from a fact graph
{dict: a, ..} -> a
dict = FactGraph.dictionary graphdata
Get the data map from a fact graph
{data: a, ..} -> a
data = FactGraph.data graphhas-errors?
Check if the fact graph has validation errors
{errors: List, ..} -> Bool
has-errors = FactGraph.has-errors? graphget-errors
Get all validation errors from the fact graph
{errors: a, ..} -> a
errors = FactGraph.get-errors graphto-map
Convert fact graph data to a plain map (for serialization)
{data: a, ..} -> a
map = FactGraph.to-map graphfrom-map
Create a fact graph from a dictionary and a plain map
a -> Map -> {dict: a, data: Map, errors: List}
graph = FactGraph.from-map dict saved-datais-valid-type?
Check if a value matches a type definition
String -> a -> Bool
valid = FactGraph.is-valid-type? "Int" 42is-valid-fact?
Check if a fact value is valid against its definition in the graph
{dict: {facts: Map, ..}, ..} -> NonEmptyString -> a -> Bool
result = FactGraph.is-valid-fact? graph "/person/age" 30