Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Syntax Overview

Dolfin uses indentation-sensitive syntax, like Python. Blocks are opened with a colon (:) and delimited by consistent indentation, tabs or spaces, but never mixed. All lines inside a block must be at the same indentation level.

Comments begin with # and run to the end of the line.


# This is a comment
concept Foo:
  has bar: string  # inline comment

File types

A Dolfin project uses two kinds of files.

package.dlf: one per project, declares the package identity:


package <http://example.com/my-ontology>:
  dolfin_version "1"
  version "0.3.0"
  author "Alice"
  description "A short description"
FieldRequiredDescription
dolfin_versionyesLanguage version to use (currently "1")
versionyesOntology version (semver string)
authornoAuthor name
descriptionnoHuman-readable description of the ontology

*.dlf ontology files: one or more files containing declarations (concepts, enums, properties, rules).


Prefixes

Prefixes bind short aliases to IRI namespaces, enabling interoperability with external vocabularies.


prefix schema as <http://schema.org/>
prefix dc as <http://purl.org/dc/elements/1.1/>

Once declared, a prefix can be used in qualified names:


has address: optional schema.PostalAddress

Prefixes can also be declared in a hierarchical block to share a common path:


prefix com.example:
  Person
  Organization as Org

This is equivalent to:


prefix com.example.Person
prefix com.example.Organization as Org

Concepts

A concept defines a category of things and the attributes they can carry.


concept Person:
  has first_name: one string
  has last_name: one string
  has email: optional string
  has age: optional int

An empty concept (no body) is also valid, useful as a flag or tag:


concept FlaggedForReview

Inheritance

A concept can inherit from one or more parents using sub:


concept Employee:
  sub Person
  has employee_id: one string
  has department: one string

concept Manager:
  sub Employee
  has reports: Employee

Multiple parents are comma-separated:


concept PartTimeEmployee:
  sub Employee, Contractor

Attributes

Each attribute is declared with has:

has <name>: [cardinality] <type>

The type can be a primitive or another concept name:


has count: one int
has owner: optional Person
has tags: string          # zero or more (default cardinality)

Cardinality

Cardinality constrains how many values an attribute can hold.

KeywordMeaning
(none)Any number (zero or more)
anyAny number (zero or more, explicit)
oneExactly one (required)
optionalZero or one
someOne or more
NExactly N (integer literal)
N..MBetween N and M (inclusive)
N..*At least N

has name: one string          # required, single value
has nickname: optional string # may be absent
has tags: some string         # at least one
has aliases: string           # any number (default)
has lucky_numbers: 3 int      # exactly three
has scores: 1..5 float        # between one and five
has comments: 0..* string     # zero or more (explicit range)

Primitive types

TypeDescriptionExamples
stringText"hello", ""
intInteger0, 42, -7
floatFloating-point3.14, -0.5
booleanBooleantrue, false

Closed concepts

An closed concept defines a closed set of named values. Only the declared variants are valid:


concept Status:
  one of:
    Pending
    Active
    Archived

Enumurated values are referenced by name in attributes and rules:


has status: one Status

Properties

A property is a named relationship declared independently of any concept, rather than inside one. It connects a domain type to a range type:


property worksFor: Employee -> Organization

Cardinality can be specified on either side:


property manages: one Manager -> Employee

Properties are used in rule patterns and assertions like any attribute.


Rules

A rule defines an if-then inference. When all patterns in the match: block hold, the assertions in the then: block are applied.


rule classify_senior:
  match:
    ?p a Person
    ?p age [ >= 65 ]
  then:
    ?p a SeniorPerson

Variables

Variables begin with ?. They bind to values during matching and can be referenced in assertions:


rule link_preferred_contact:
  match:
    ?org a Organization
    ?org primary_contact ?person
  then:
    ?person worksFor ?org

Match patterns

Each line in match: is a pattern. All patterns are combined with implicit AND.

Type pattern: checks that a variable is an instance of a concept:


?x a SomeConcept

Triple pattern: checks that a subject has a property with a given value:


?x someProperty someValue
?x someProperty ?y
?x someProperty "literal"
?x someProperty 42

Constraint block: inline conditions on a value using [...]:


?x age [ > 18 ]
?x status [ = Active ]
?x address [ city "Paris" ]
?x manager [ a Director ]

Multiple constraints in a block are AND-combined:


?x score [ >= 50, <= 100 ]

Constraint blocks can be nested:


?x owner [ address [ country "France" ] ]

Comparison operators

Used inside constraint blocks:

OperatorMeaning
=Equal
!=Not equal
<Less than
<=Less than or equal
>Greater than
>=Greater than or equal

Quantifiers

Quantifiers express conditions over collections of matching bindings:

QuantifierMeaning
allEvery binding must satisfy the sub-patterns
noneNo binding may satisfy the sub-patterns
at_least NAt least N bindings must satisfy the sub-patterns
at_most NAt most N bindings may satisfy the sub-patterns
exactly NExactly N bindings must satisfy the sub-patterns
between N, MBetween N and M bindings (inclusive)

rule require_manager_approval:
  match:
    ?req a Request
    none ?approver:
      ?approver a Manager
      ?req approvedBy ?approver
  then:
    ?req a UnapprovedRequest

An optional constraint block on the quantifier variable filters the set being quantified:


at_least 2 ?member [ a SeniorEmployee ]:
  ?member worksIn ?dept

Then assertions

Each line in then: asserts a new fact:

Type assertion: classifies a variable as an instance of a concept:


?x a SomeConcept

Triple assertion: asserts a property relationship:


?x someProperty ?y
?x someProperty "value"

Nested rules

A then: block can contain a nested match:/then: block for conditional sub-inferences:


rule complex_inference:
  match:
    ?x a Foo
  then:
    match:
      ?x bar ?y
    then:
      ?y a Baz

Names and identifiers

Simple names are alphanumeric identifiers (with underscores): Person, first_name, status.

Qualified names use dot-notation to reference names in a namespace: schema.Person, com.example.Thing.

IRIs are enclosed in angle brackets: <http://example.com/Thing>. They can appear as package names and prefix targets.

Variables begin with ?: ?person, ?count.


The @iri_name annotation

The @iri_name annotation overrides the IRI segment derived from a file’s name. It appears at the top of an ontology file, before any declarations:


@iri_name "custom-segment"

concept Foo:
  has bar: string

This is useful when the file name doesn’t match the IRI fragment expected by external systems.