Skip to main content

Relations

Relations are tables — they hold rows of typed data. Every relation starts with a .decl and can be annotated with .input, .output, or .printsize to control how data flows in and out.

Declaring a relation

Use .decl to define a relation's schema — its name and the type of each column:

.decl Edge(src: int32, dst: int32)
.decl Person(id: int64, name: string, active: bool)

Every column needs an explicit type. No column can be left untyped.

I/O annotations

.input, .output, and .printsize are annotations — they're not mutually exclusive. Stick any combination on a relation:

AnnotationWhat it does
.inputLoad facts from a CSV file (or the interactive shell in incremental mode)
.outputWrite the relation's final contents to a file (or stderr)
.printsizePrint the tuple count after execution

The key idea: a relation with .input can also appear in rule heads and carry .output. You just annotate what goes in and what comes out — FlowLog doesn't force an "input-only vs computed-only" split.

.decl Reach(x: int32, y: int32)
.input Reach(IO="file", filename="Reach.csv", delimiter=",")

// Extend loaded seed pairs with transitive closure
Reach(x, z) :- Reach(x, y), Reach(y, z).

.output Reach

Here Reach loads seed pairs from CSV, a rule derives the transitive closure on top, and .output writes the full result.

Inline facts

You can write facts directly in the source file:

.decl Edge(src: int32, dst: int32)
Edge(1, 2).
Edge(2, 3).
Edge(3, 4).

These get merged with any file-loaded data. Handy for small seed sets or test fixtures.

.input in detail

.decl Arc(x: int32, y: int32)
.input Arc(IO="file", filename="Arc.csv", delimiter=",")
ParameterDescriptionExample
IO"file" for CSV, "cmd" for interactive shellIO="file"
filenamePath to the CSV filefilename="Arc.csv"
delimiterColumn separatordelimiter=","

The compiler flag -F <DIR> sets the base directory for filename. So -F data + filename="Arc.csv" reads data/Arc.csv.

Use IO="cmd" for incremental mode — inputs come from the interactive shell instead of files.

.output in detail

.decl Reach(id: int32)
.output Reach

The compiler flag -D <DIR> controls where output CSVs land. Pass -D - to print tuples to stderr instead — useful for quick debugging.

.printsize in detail

.decl Reach(id: int32)
.printsize Reach

Prints the number of tuples after execution. You can combine it with .output on the same relation — get both the count and the data.

Putting it all together

.decl Source(id: int32)
.input Source(IO="file", filename="Source.csv", delimiter=",")

.decl Arc(x: int32, y: int32)
.input Arc(IO="file", filename="Arc.csv", delimiter=",")

.decl Reach(id: int32)
.printsize Reach

Reach(y) :- Source(y).
Reach(y) :- Reach(x), Arc(x, y).

Validation

The compiler catches common mistakes at parse time:

  • Using a directive on a relation that hasn't been declared.
  • Duplicate .input, .output, or .printsize on the same relation.