aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMarcos Magueta <maguetamarcos@gmail.com>2026-07-11 02:35:53 -0300
committerMarcos Magueta <maguetamarcos@gmail.com>2026-07-11 02:35:53 -0300
commit66fe3a753df22f701c6c36f6fd28b45f60d460cf (patch)
tree4a962a71a37e36c306e11700535e238f4d5d3842
parentacf837b4500e15caae2d920e49113a3bf6cb45d8 (diff)
downloadSOL-66fe3a753df22f701c6c36f6fd28b45f60d460cf.tar.gz
SOL-66fe3a753df22f701c6c36f6fd28b45f60d460cf.zip
language specification document
-rw-r--r--docs/language-specification.org1336
1 files changed, 1336 insertions, 0 deletions
diff --git a/docs/language-specification.org b/docs/language-specification.org
new file mode 100644
index 0000000..9158130
--- /dev/null
+++ b/docs/language-specification.org
@@ -0,0 +1,1336 @@
+#+TITLE: Sol Language Specification
+#+AUTHOR: Marcos Magueta
+
+* Introduction
+
+Sol is a total (from [[https://en.wikipedia.org/wiki/Total_functional_programming][totality]]) relational language inspired by Prolog,
+Coq, relational algebra, constraint logic programming, and
+message-oriented syntax of Smalltalk.
+
+The central idea of Sol is that relations are the primary semantic
+objects of the language. Types are not separate from logic. Rather,
+types are relations used as membership constraints. A program in Sol
+is therefore not primarily a sequence of instructions, but a
+structured logical expression made from relation unifications,
+conjunctions, constraints, and rules.
+
+Sol is intentionally not Turing complete, but still expressive. Its
+purpose is not to express arbitrary machine computation, but achieve
+something close through dependent relational typing. There's a large
+set of problems that can still be solved even if the language is not
+turing complete. For example: arithmetic, data structure algorithms,
+parsers, compilers, theorem provers, symbolic manipulators, certified
+interpreters, graph algorithms, sorting, balancing trees, type
+checkers, relational evaluators and normalization procedures; so long
+as their structures can be normalized and the whole can be proven
+total.
+
+In other words, Sol is a language that has no mu-recursion (unbounded
+minimization), instead implementing primitive recursion through
+fixpoint; while not having partial expressions.
+
+* Core Design Intention
+
+Sol is designed around the following principles:
+
+- Relations are the primary objects
+- Types are relations
+- Domains are unary relations (to represent atomicity) with special
+ operational capabilities
+- Explicit conjunction and disjunction
+- Joins happen through unification
+- Variables are logical unknowns
+- Infinite domains are membership constraints by default, not
+ enumerators, but can be enumerated as subsets
+- Totality is mandatory
+- Execution is proof search, constraint propagation, and
+ normalization
+- Syntax should remain Smalltalk-like: atoms, labels ending in colons,
+ literals, variables, and blocks.
+
+* Lexical Categories
+
+Sol keeps the surface syntax deliberately small.
+
+The core lexical categories are:
+
+- atoms
+- labels
+- variables
+- literals (ground scalars)
+- records (tuple literals)
+- sequences (list literals)
+- blocks (membership propositions)
+- logical combinator messages as labels
+
+Each delimiter has exactly one role, and the roles do not overlap:
+
+| Delimiter | Role |
+|--------------------+---------------------------------------------|
+| =[ ... ]= | membership proposition (relation application) |
+| ={ ... }= | record (labeled tuple) term |
+| =#( ... )= | sequence (list) term |
+| =( ... )= | grouping of a relational expression |
+
+A =[= never opens a list, a ={= never opens a proposition, and
+grouping never uses square brackets.
+
+** Atoms
+
+Atoms name relations, domains, query forms, and other language-level receivers.
+
+Examples:
+
+#+BEGIN_SRC sol
+Integer
+Person
+Adult
+Plus
+Length
+Query
+Relation
+#+END_SRC
+
+Atoms begin with lowercase or uppercase letters, but by convention relation names are capitalized.
+
+** Labels
+
+Labels are attribute names ending or beginnign with a colon.
+
+Examples:
+
+#+BEGIN_SRC sol
+value:
+left:
+right:
+result:
+name:
+age:
+person:
+list:
+#+END_SRC
+
+Labels are not positional argument markers. They name the attributes
+of a relation.
+
+For example:
+
+#+BEGIN_SRC sol
+[Plus left: X right: Y result: R]
+#+END_SRC
+
+means that the relation =Plus= has labeled attributes =left=, =right=,
+and =result=.
+
+** Variables
+
+Variables begin with uppercase identifiers, just like atoms. We
+distinguish them by context.
+
+Examples:
+
+#+BEGIN_SRC sol
+ X
+ Y
+ R
+ PersonId
+ Age
+ Tail
+ Partial
+#+END_SRC
+
+Variables are logical variables. They may be unified with literals,
+other variables, or structured values.
+
+Variables are not assigned procedurally. They are constrained by
+relation "applications".
+
+** Literals
+
+A literal is not a separate ontological category. Every literal is
+canonical notation for a member of some domain — a tuple inhabiting a
+domain relation.
+
+Examples:
+
+#+BEGIN_SRC sol
+ 0
+ 1
+ 22
+ "Sun"
+ 1/4
+ #()
+#+END_SRC
+
+- =123= denotes a member of the =Integer= domain;
+- ="Sun"= denotes a member of =String=;
+- =1/4= is one token (no interior whitespace), denoting the tuple
+ ={numerator: 1 denominator: 4}= as a member of =Rational= — the
+ constraint that the denominator is a nonzero integer is a
+ membership criterion on that tuple, where it belongs;
+- =#()= denotes the empty sequence.
+
+Composite values are labeled tuples of members, uniformly. The
+recursion bottoms out at ground scalars (integers, strings, and
+kin), whose membership is decided by the host world's builtin
+membership criteria (see Membership Criteria).
+
+** Records
+
+A record is the written form of a labeled tuple — the central
+semantic object of the language:
+
+#+BEGIN_SRC sol
+{name: "Marcos" age: 30}
+
+{numerator: 1 denominator: 4}
+
+{head: H tail: T}
+#+END_SRC
+
+A record is a *term*: it asserts nothing. A membership proposition
+=[R l1: t1 l2: t2]= is precisely the assertion that the record
+={l1: t1 l2: t2}= belongs to the relation =R=. Relation application
+is therefore record-plus-membership, and this elaboration is
+normative:
+
+#+BEGIN_EXAMPLE
+[R l1: t1 ... ln: tn] ≡ {l1: t1, ..., ln: tn} ∈ R
+#+END_EXAMPLE
+
+Label order in records is irrelevant, as in applications.
+
+** Sequences
+
+A sequence is list-literal sugar, written =#( ... )= (after
+Smalltalk's array literal):
+
+#+BEGIN_SRC sol
+#()
+
+#(1 2 3)
+
+#(Head | Tail)
+#+END_SRC
+
+Its elaboration into tuples is normative: a nonempty list is the
+tuple ={head: H tail: T}=, and the empty list is the distinguished
+member =#()=, so
+
+#+BEGIN_EXAMPLE
+#(1 2 3) ≡ {head: 1 tail: {head: 2 tail: {head: 3 tail: #()}}}
+#(Head | Tail) ≡ {head: Head tail: Tail}
+#+END_EXAMPLE
+
+=#(Head | Tail)= is thus a tuple pattern, not a special form. A
+sequence of propositions (e.g. a schema's fact list) also uses
+=#( ... )=: it is honestly a sequence whose elements happen to be
+blocks.
+
+** Blocks
+
+Blocks — square brackets — delimit exactly one thing: membership
+propositions (relation applications). They are never list literals,
+never grouping, never sequences.
+
+Examples:
+
+#+BEGIN_SRC sol
+[Integer value: X]
+
+[Plus left: X right: Y result: R]
+#+END_SRC
+
+Grouping of a relational expression, where precedence demands it,
+uses parentheses:
+
+#+BEGIN_SRC sol
+([Integer value: X] :and [LessThanEqual left: X right: 120])
+#+END_SRC
+
+A relation, just like other structures, should be understood as an
+object (we will talk about secondary types), and as such, it should be
+able to support messages such as composition with logical combinators,
+like =:and= or =:or=. Notice that such combinators are different
+labels, given their orientation of colon. They are used for messages
+to objects, in this case, =Relation=.
+
+* Relation Application Syntax
+
+A relation application has the form:
+
+#+BEGIN_SRC sol
+[Relation label: Term label: Term ...]
+#+END_SRC
+
+Examples:
+
+#+BEGIN_SRC sol
+[Integer value: X]
+
+[Person id: P name: "Damian" age: A]
+
+[Plus left: X right: Y result: R]
+#+END_SRC
+
+The order of labels should not matter semantically, provided the
+labels are unique and recognized by the relation schema. The internal
+representation should be closer to a labeled record/map than to a
+positional tuple.
+
+Thus these should normalize to the same relation application:
+
+#+BEGIN_SRC sol
+[Plus left: X right: Y result: R]
+
+[Plus result: R right: Y left: X]
+#+END_SRC
+
+* Conjunction
+
+Conjunction is expressed explicitly with the message =:and=.
+
+Example:
+
+#+BEGIN_SRC sol
+ [Integer value: X] :and [Integer value: Y] :and [Plus left: X right: Y result: R]
+#+END_SRC
+
+This means:
+
+#+BEGIN_EXAMPLE
+ Integer(X) ∧ Integer(Y) ∧ Plus(X,Y,R)
+#+END_EXAMPLE
+
+There is no implicit newline-based conjunction in the core syntax, and
+this is important, as the following should not be treated as a
+conjunction merely because two expressions are adjacent:
+
+#+BEGIN_SRC sol
+ [Integer value: X]
+ [Integer value: Y]
+#+END_SRC
+
+Instead, conjunction must be explicit:
+
+#+BEGIN_SRC sol
+ [Integer value: X] :and
+ [Integer value: Y]
+#+END_SRC
+
+* Query Syntax
+
+A query is a named wrapper around a relational expression. The result
+of a query itself is another relation object, that is in turn
+constructed atop of the other relations through conjunction.
+
+Example:
+
+#+BEGIN_SRC sol
+ Query expression:
+ [Integer value: X] :and
+ [Integer value: Y] :and
+ [Plus left: X right: Y result: 10]
+#+END_SRC
+
+This means:
+
+#+BEGIN_EXAMPLE
+∃ X Y .
+ Integer(X) ∧ Integer(Y) ∧ Plus(X,Y,10)
+#+END_EXAMPLE
+
+The query body is not a sequence of statements, it is one relational
+expression, built from relation applications and logical combinators.
+
+* Joins Through Unification
+
+Joins are expressed by sharing variables across relation
+applications. We can say that conjunctions with unifications are
+joins.
+
+Example:
+
+#+BEGIN_SRC sol
+Query expression:
+ [Person id: P name: "Marcos"] :and
+ [Adult person: P]
+#+END_SRC
+
+The shared variable =P= is the join point.
+
+Semantically:
+
+#+BEGIN_EXAMPLE
+∃ P .
+ Person(id=P, name="Marcos")
+∧ Adult(person=P)
+#+END_EXAMPLE
+
+No explicit join operator is necessary.
+
+* Domains as Unary Relations
+
+Domains are unary relations with special operational capabilities. A
+domain is not fundamentally separate from a relation, it is a relation
+with one principal attribute =value:=.
+
+Domains may support different modes:
+
+- membership checking
+- constraint attachment
+- literal validation
+- optional bounded generation
+
+However, domains do not enumerate by default, as they are potentially
+aleph zero in cardinality.
+
+Example:
+
+#+BEGIN_SRC sol
+ [Integer value: X]
+#+END_SRC
+
+means:
+
+#+BEGIN_EXAMPLE
+X ∈ Integer
+#+END_EXAMPLE
+
+or:
+
+#+BEGIN_EXAMPLE
+Integer(X)
+#+END_EXAMPLE
+
+* Infinite Domains
+
+A crucial distinction in Sol is between membership and generation.
+
+The expression:
+
+#+BEGIN_SRC sol
+ [Integer value: X]
+#+END_SRC
+
+does not mean:
+
+#+BEGIN_EXAMPLE
+Generate every integer X.
+#+END_EXAMPLE
+
+It means:
+
+#+BEGIN_EXAMPLE
+Constrain X to be an integer.
+#+END_EXAMPLE
+
+This is essential for totality, as the same applies to other countably
+infinite domains:
+
+#+BEGIN_SRC sol
+ [Rational value: Q]
+
+ [String value: S]
+
+ [List element: Integer value: XS]
+#+END_SRC
+
+These expressions constrain membership, and do not automatically
+enumerate all possible inhabitants. Generation must be explicit and
+controlled by the language. For example, a future generation form
+might look like:
+
+#+BEGIN_SRC sol
+ [Generate domain: Integer value: X]
+#+END_SRC
+
+However unbounded generation over infinite domains should either be
+rejected, delayed, bounded, or placed outside the total fragment (a
+subset).
+
+* Relation Schemas
+
+A relation has a schema: a set of accepted labels and their expected
+domains. A possible declaration form:
+
+#+BEGIN_SRC sol
+Relation named: Person schema: #(
+ [name domain: String]
+ [age domain: ([Natural value: X] :and [LessThanEqual left: X right: 120])]
+)
+#+END_SRC
+
+This declaration says that =Person= admits the labels:
+
+- =name:=
+- =age:=
+
+and that each attribute is constrained by its declared domain
+criterion: =name:= by membership in =String=, and =age:= by the
+refinement "a =Natural= at most 120".
+
+This declaration syntax is provisional, but it should obey the same
+principle as the rest of Sol: internal bodies should be explicit
+relational expressions, not implicit statement sequences. In this
+definition, we are dealing with a list of facts, not with a single
+expression, hence the sequence =#( ... )= — visibly a sequence whose
+elements are propositions, not itself a proposition.
+
+* Rules
+
+A rule defines one relation in terms of another relational
+expression. A possible rule form:
+
+#+BEGIN_SRC sol
+ Rule name: "Adult is a person with age greater than 18"
+ head: [Adult person: P]
+ body: [Person id: P age: A] :and
+ [GreaterEqual left: A right: 18]
+#+END_SRC
+
+This means:
+
+#+BEGIN_EXAMPLE
+Adult(P) ⇐ Person(P,A) ∧ GreaterEqual(A,18)
+#+END_EXAMPLE
+
+The body is explicitly a conjunction.
+
+It is not written as:
+
+#+BEGIN_SRC sol
+ Person id: P age: A
+ GreaterEqual left: A right: 18
+#+END_SRC
+
+because that would reintroduce implicit sequencing.
+
+* Operational Capabilities
+
+Relations may declare operational capabilities.
+
+For example:
+
+#+BEGIN_SRC sol
+Relation named: Plus capabilities: #(
+ [Capability name: evaluate]
+ [Capability name: solve]
+ [Capability name: constrain]
+)
+#+END_SRC
+
+The exact declaration syntax is provisional, but the semantic idea is
+important.
+
+A relation may support:
+
+- membership checking :: given a tuple (eg [left: 1 right: 2 result:
+ 3] is of type Plus) see if it belongs to the relation
+- evaluation
+- backward solving
+- symbolic constraint propagation
+- finite enumeration
+- bounded generation :: for infinite generators, we must only operate
+ on subsets when enumerating, from for example a higher order
+ predicate Take[predicate: P many: N]
+- rewriting
+- normalization
+
+Operational capabilities are not the relation's meaning. They are the
+allowed ways the runtime may use the relation during proof search.
+
+* Modes
+
+Sol should not require ordinary query syntax to annotate every
+argument as input or output.
+
+Instead of writing =+= for inputs and =-= for outputs, as in:
+
+#+BEGIN_SRC sol
+ [Plus +left: X +right: Y -result R]
+#+END_SRC
+
+the preferred surface form is:
+
+#+BEGIN_SRC sol
+ [Plus left: X right: Y result: R]
+#+END_SRC
+
+The operational mode is inferred from:
+
+- bound variables
+- domain constraints
+- relation capabilities
+- solver availability
+- totality restrictions
+
+Though =+= and =-= are not necessary, we might want to still annotate
+them to help the planning.
+
+* Equality
+
+Equality may be represented as a relation.
+
+Example:
+
+#+BEGIN_SRC sol
+[Equal left: X right: Y]
+#+END_SRC
+
+Equality may perform unification, literal comparison, or symbolic
+constraint propagation.
+
+Examples:
+
+#+BEGIN_SRC sol
+Query expression:
+ [Equal left: X right: 10] :and
+ [Plus left: X right: 5 result: R]
+#+END_SRC
+
+This should bind or constrain =X= to =10=, then relate =R= to =15=.
+
+* Disjunction
+
+Disjunction may be expressed with =:or=.
+
+Example:
+
+#+BEGIN_SRC sol
+[Color value: "red"] :or
+[Color value: "blue"]
+#+END_SRC
+
+Disjunction introduces branching proof search.
+
+To preserve totality, disjunction must be finite or otherwise controlled.
+
+* Negation
+
+Negation must be restricted to the world that is being denied, as a
+negation has to come from something. World is a relation where every
+relation is part of it, and it cannot be enumerated.
+
+A possible syntax:
+
+#+BEGIN_SRC sol
+[World] :not [Adult person: P]
+#+END_SRC
+
+Semantically, Sol should support only stratified negation or decidable
+negation over finite/proven domains.
+
+Unrestricted negation-as-failure should not be admitted into the total
+core.
+
+* Membership Criteria
+
+A membership criterion is a relational expression used to determine
+whether a tuple belongs to a relation. In Sol, there is no fundamental
+distinction between a type check, an integrity constraint, and a
+relational membership check. All of them are expressed as relations.
+
+For example:
+
+#+BEGIN_SRC sol
+ [Integer value: X]
+#+END_SRC
+
+means that the tuple ={value: X}= must belong to the unary relation
+=Integer=, which is in itself a domain.
+
+Likewise:
+
+#+BEGIN_SRC sol
+ [Plus left: X right: Y result: R]
+#+END_SRC
+
+means that the labeled tuple ={left: X, right: Y, result: R}= must
+belong to the relation =Plus=.
+
+This is the general form:
+
+#+BEGIN_SRC sol
+ [Relation label: Term label: Term ...]
+#+END_SRC
+
+Semantically, this asks whether the labeled tuple belongs to
+=Relation=.
+
+For example:
+
+#+BEGIN_SRC sol
+[Person id: P name: "Marcos" age: A]
+#+END_SRC
+
+means:
+
+#+BEGIN_EXAMPLE
+{id = P, name = "Marcos", age = A} ∈ Person
+#+END_EXAMPLE
+
+A membership criterion should be defined for each relation or default
+to an attempt at unifying the members into it. On a domain Integer,
+for example, the host language may construct a builtin membership
+criteria that simply checks if the tuple {value: <literal_integer>}
+satisfies that, value is indeed an integer at the host language in
+which Sol is programmed in. Optionally we can define such as a rule
+for each, for example, rationals can bear a constraint that validates
+if the numerator and denominator are integers, but that the
+denominator is different from zero. Those are thus, quick ways to
+determine membership without having to resort to searching the space
+of the relation, specially since some relations are impossible to
+enumerate, but we still can tell its members apart. A last example,
+the World relation should yield true for every tuple assigned to it.
+
+A membership criterion may be used:
+
+- as a type-like assertion;
+- as a query goal;
+- as an integrity constraint;
+- as part of a rule body;
+- as a relation schema refinement;
+- as a symbolic constraint.
+
+Some examples of ordinary relations that are also constraints:
+
+#+BEGIN_SRC sol
+[Equal left: X right: Y]
+
+[LessThan left: A right: B]
+
+[GreaterEqual left: Score right: 0]
+
+[LessThanEqual left: Score right: 100]
+#+END_SRC
+
+There is no special built-in equality predicate required at the
+surface level. Equality may be treated as an ordinary relation with
+special operational capabilities, such as unification, literal
+comparison, and symbolic rewriting.
+
+** Membership as Integrity Control
+
+An integrity constraint is a membership criterion attached to a target
+relation.
+
+For example, a score must be between 0 and 100:
+
+#+BEGIN_SRC sol
+Constraint
+ name: "score_range"
+ relation: Result
+ body:
+ [GreaterEqual left: Score right: 0] :and
+ [LessThanEqual left: Score right: 100]
+#+END_SRC
+
+The variables in the constraint body are interpreted relative to the
+tuple being checked.
+
+If the target relation has a label =score:=, the constraint may bind
+that attribute explicitly:
+
+#+BEGIN_SRC sol
+Constraint
+ name: "score_range"
+ relation: Result
+ body:
+ [Current label: score value: Score] :and
+ [GreaterEqual left: Score right: 0] :and
+ [LessThanEqual left: Score right: 100]
+#+END_SRC
+
+Here =Current= denotes the tuple currently being checked.
+
+This preserves the same principle as Sakura's ICL: before accepting a
+tuple into a relation, the system verifies that the tuple satisfies
+all constraint-relations attached to the target relation.
+
+** Membership as Foreign Key
+
+A foreign key is just a membership check against another relation.
+
+Example:
+
+#+BEGIN_SRC sol
+Constraint
+ name: "fk_employee_dept"
+ relation: Employee
+ body:
+ [Current label: dept_id value: DeptId] :and
+ [Department dept_id: DeptId]
+#+END_SRC
+
+This means:
+
+#+BEGIN_EXAMPLE
+For the current Employee tuple, its dept_id must appear as the dept_id
+of some Department tuple.
+#+END_EXAMPLE
+
+No special foreign-key syntax is required. Foreign keys are relation
+membership criteria.
+
+** Membership as Refinement
+
+A schema entry may use a membership criterion as a refinement.
+
+Example:
+
+#+BEGIN_SRC sol
+Relation named: Result schema: #(
+ [student_id domain: Integer]
+ [score domain:
+ ([Integer value: Score] :and
+ [GreaterEqual left: Score right: 0] :and
+ [LessThanEqual left: Score right: 100])]
+)
+#+END_SRC
+
+This means that =score:= is not merely an integer. It is an integer
+that belongs to the refinement relation:
+
+#+BEGIN_EXAMPLE
+Score ∈ Integer ∧ Score ≥ 0 ∧ Score ≤ 100
+#+END_EXAMPLE
+
+The variable introduced in the refinement expression is local to that
+schema entry unless explicitly connected to another variable by the
+schema mechanism.
+
+** Membership and Totality
+
+Membership checking must be total.
+
+Given a fully grounded tuple, a membership criterion must either:
+
+- succeed;
+- fail;
+- or produce a finite, decidable set of residual constraints.
+
+It must not diverge, and for infinite domains, membership is allowed
+but unbounded enumeration is not.
+
+Thus:
+
+#+BEGIN_SRC sol
+[Integer value: X]
+#+END_SRC
+
+with =X= unbound constrains =X= to the domain =Integer=. It does not
+enumerate all integers.
+
+Enumeration must be expressed separately, and only through a bounded
+or otherwise total subset.
+
+Example:
+
+#+BEGIN_SRC sol
+[Take relation: Integer count: 10 value: X]
+#+END_SRC
+
+or:
+
+#+BEGIN_SRC sol
+[Between value: X lower: 0 upper: 10]
+#+END_SRC
+
+The exact enumeration syntax is provisional, but the principle is not:
+membership is not generation.
+* Existential Quantification
+
+Existential quantification states that there exists at least one value
+in a relation satisfying a body. In Sol, existential quantification is
+already implicit in ordinary queries and rule bodies.
+
+For example:
+
+#+BEGIN_SRC sol
+Query expression:
+ [Person id: P name: "Marcos"] :and
+ [Adult person: P]
+#+END_SRC
+
+means:
+
+#+BEGIN_EXAMPLE
+∃ P .
+ Person(id=P, name="Marcos") ∧ Adult(person=P)
+#+END_EXAMPLE
+
+A variable that appears in a query expression is existentially
+quantified unless it is explicitly bound by an outer context.
+
+** Explicit Exists
+
+Sol may also provide an explicit existential form.
+
+A possible syntax:
+
+#+BEGIN_SRC sol
+[Exists variable: P
+ domain: PersonId
+ body:
+ [Person id: P name: "Marcos"] :and
+ [Adult person: P]]
+#+END_SRC
+
+This means:
+
+#+BEGIN_EXAMPLE
+∃ P ∈ PersonId .
+ Person(id=P, name="Marcos") ∧ Adult(person=P)
+#+END_EXAMPLE
+
+The =domain:= label is a membership criterion that restricts the
+search space of the variable.
+
+For unary domains, this:
+
+#+BEGIN_SRC sol
+domain: PersonId
+#+END_SRC
+
+is shorthand for:
+
+#+BEGIN_SRC sol
+[PersonId value: P]
+#+END_SRC
+
+A more explicit form may be preferable where the quantified relation
+has named labels:
+
+#+BEGIN_SRC sol
+[Exists variable: P
+ quantifier: [PersonId value: P]
+ body:
+ [Person id: P name: "Marcos"] :and
+ [Adult person: P]]
+#+END_SRC
+
+This form generalizes better, because =quantifier:= may be any
+membership criterion.
+
+** Existential Through a Join
+
+A foreign key through a join can be expressed existentially.
+
+Example: a suite is valid if its room belongs to a building with more
+than three floors.
+
+#+BEGIN_SRC sol
+Constraint
+ name: "suite_in_tall_building"
+ relation: Suite
+ body:
+ [Current label: room_id value: RoomId] :and
+ [Exists variable: R
+ quantifier: [Room room_id: RoomId building_id: BuildingId]
+ body:
+ [Exists variable: B
+ quantifier: [Building building_id: BuildingId floors: Floors]
+ body:
+ [GreaterThan left: Floors right: 3]]]
+#+END_SRC
+
+The semantics are:
+
+#+BEGIN_EXAMPLE
+For the current Suite tuple, there exists a Room with the same room_id,
+and there exists a Building with the Room's building_id, such that the
+Building has more than 3 floors.
+#+END_EXAMPLE
+
+This is equivalent to a relational join:
+
+#+BEGIN_EXAMPLE
+Suite.room_id = Room.room_id
+Room.building_id = Building.building_id
+Building.floors > 3
+#+END_EXAMPLE
+
+But no special join operator is needed. The join is expressed by
+shared variables.
+
+** Existential Variables in Rule Bodies
+
+Variables that appear in a rule body but not in the rule head are
+existential relative to the rule.
+
+Example:
+
+#+BEGIN_SRC sol
+Rule
+ name: "Adult is a person with age greater than or equal to 18"
+ head: [Adult person: P]
+ body:
+ [Person id: P age: A] :and
+ [GreaterEqual left: A right: 18]
+#+END_SRC
+
+Here =A= is existentially quantified in the body.
+
+The rule means:
+
+#+BEGIN_EXAMPLE
+Adult(P) ⇐ ∃ A .
+ Person(id=P, age=A) ∧ A ≥ 18
+#+END_EXAMPLE
+
+** Totality Requirements for Exists
+
+Existential quantification is only admitted into the total fragment
+when its search space is finite, bounded, structurally decreasing, or
+solvable symbolically.
+
+This is valid if =PersonId= is finite or indexed:
+
+#+BEGIN_SRC sol
+[Exists variable: P
+ quantifier: [Person id: P name: "Marcos"]
+ body: [Adult person: P]]
+#+END_SRC
+
+This is dangerous if it requires unbounded enumeration:
+
+#+BEGIN_SRC sol
+[Exists variable: X
+ quantifier: [Integer value: X]
+ body: [GreaterThan left: X right: 100]]
+#+END_SRC
+
+The latter must not enumerate integers until it finds one. It must be
+handled symbolically, bounded explicitly, or rejected from the total
+fragment.
+
+For example, this is admissible:
+
+#+BEGIN_SRC sol
+[Exists variable: X
+ quantifier: [Between value: X lower: 0 upper: 1000]
+ body: [GreaterThan left: X right: 100]]
+#+END_SRC
+
+because the quantifier relation is bounded.
+
+* Universal Quantification
+
+Universal quantification states that every value in a relation
+satisfies a body.
+
+A possible syntax:
+
+#+BEGIN_SRC sol
+[ForAll variable: X
+ quantifier: [Integer value: X]
+ body: [GreaterEqual left: X right: 0]]
+#+END_SRC
+
+This means:
+
+#+BEGIN_EXAMPLE
+∀ X ∈ Integer .
+ X ≥ 0
+#+END_EXAMPLE
+
+This particular example is false, because not all integers are greater
+than or equal to zero.
+
+A true version would use =Natural=:
+
+#+BEGIN_SRC sol
+[ForAll variable: X
+ quantifier: [Natural value: X]
+ body: [GreaterEqual left: X right: 0]]
+#+END_SRC
+
+** Universal Quantification Over Finite Relations
+
+Universal quantification is straightforward over finite stored
+relations.
+
+Example: every result score must be between 0 and 100.
+
+#+BEGIN_SRC sol
+[ForAll variable: R
+ quantifier: [Result id: R score: Score]
+ body:
+ [GreaterEqual left: Score right: 0] :and
+ [LessThanEqual left: Score right: 100]]
+#+END_SRC
+
+This means:
+
+#+BEGIN_EXAMPLE
+For every tuple in Result, its score is between 0 and 100.
+#+END_EXAMPLE
+
+Operationally, this can be checked by scanning the finite relation
+=Result= or by registering the condition as an integrity constraint
+checked on every insert/update.
+
+** Universal Quantification as Integrity Control
+
+A relation-level integrity constraint can often be understood as a
+universal statement.
+
+For example:
+
+#+BEGIN_SRC sol
+Constraint
+ name: "all_scores_are_in_range"
+ relation: Result
+ body:
+ [Current label: score value: Score] :and
+ [GreaterEqual left: Score right: 0] :and
+ [LessThanEqual left: Score right: 100]
+#+END_SRC
+
+corresponds to:
+
+#+BEGIN_EXAMPLE
+∀ tuple ∈ Result .
+ tuple.score ≥ 0 ∧ tuple.score ≤ 100
+#+END_EXAMPLE
+
+The constraint form is operationally preferable because it turns a
+global universal condition into a local membership check on each tuple
+mutation.
+
+This is the integrity-control interpretation:
+
+#+BEGIN_EXAMPLE
+A tuple may be inserted into relation R only if it belongs to every
+constraint-relation attached to R.
+#+END_EXAMPLE
+
+** Universal Quantification and Negation
+
+Universal quantification may be reduced to negated existence when the
+negation is decidable and the world is controlled:
+
+#+BEGIN_EXAMPLE
+∀ x ∈ R . P(x)
+≡
+¬ ∃ x ∈ R . ¬ P(x)
+#+END_EXAMPLE
+
+In Sol syntax, a possible form is:
+
+#+BEGIN_SRC sol
+[ForAll variable: X
+ quantifier: [Result id: X score: Score]
+ body:
+ [GreaterEqual left: Score right: 0] :and
+ [LessThanEqual left: Score right: 100]]
+#+END_SRC
+
+which may be planned internally as:
+
+#+BEGIN_SRC sol
+[World relation: Result] :not
+ [Exists variable: X
+ quantifier: [Result id: X score: Score]
+ body:
+ [LessThan left: Score right: 0] :or
+ [GreaterThan left: Score right: 100]]
+#+END_SRC
+
+This transformation is only valid when the negated world is decidable:
+for example, a finite stored relation, an indexed finite subset, or a
+symbolically decidable domain.
+
+** Universal Quantification Over Infinite Domains
+
+Universal quantification over infinite domains must not be implemented
+by enumeration.
+
+For example:
+
+#+BEGIN_SRC sol
+[ForAll variable: X
+ quantifier: [Integer value: X]
+ body:
+ [Equal left: [Plus left: X right: 0] right: X]]
+#+END_SRC
+
+This should be proved symbolically, by the algebraic properties of
+=Plus= and =Equal=, not by checking every integer.
+
+If Sol cannot prove such a universal symbolically, it must reject the
+program, keep it as an unproven obligation, or require an explicit
+trusted theorem/certificate.
+
+** Totality Requirements for ForAll
+
+Universal quantification is admitted when one of the following holds:
+
+- the quantified relation is finite;
+- the quantified relation is a bounded subset;
+- the body is decidable for every member of the quantified relation;
+- the universal can be discharged symbolically;
+- the universal is converted to a finite integrity-control check;
+- a totality/proof certificate is supplied.
+
+Universal quantification over an infinite domain with an undecidable
+body is not admitted into the total core.
+
+Thus this should be rejected or left as an obligation:
+
+#+BEGIN_SRC sol
+[ForAll variable: X
+ quantifier: [Integer value: X]
+ body: [SomeArbitraryRelation value: X]]
+#+END_SRC
+
+unless =SomeArbitraryRelation= has a declared decidable membership
+procedure or proof certificate.
+* Recursion
+
+Recursive rules are allowed only when the system can prove
+totality. Recursive calls must be structurally decreasing, guarded,
+finite, or otherwise accepted by a termination checker. The syntax
+must still use explicit conjunction.
+
+The body in the first rule is a relation that is simply true, called
+True.
+
+A corrected example:
+
+#+BEGIN_SRC sol
+ Rule
+ name: "An empty list is always true"
+ head: [Length list: #() result: 0]
+ body: [True]
+
+ Rule
+ name: "A list tail is summed"
+ head: [Length list: #(Head | Tail) result: R]
+ body: [Length list: Tail result: Partial] :and
+ [Plus left: 1 right: Partial result: R]
+#+END_SRC
+
+The recursive call is accepted only if the termination checker can
+see that =Tail= is structurally smaller than =#(Head | Tail)= — that
+is, than the tuple ={head: Head tail: Tail}= it elaborates to.
+
+An invalid rule:
+
+#+BEGIN_SRC sol
+ Rule
+ name: "Loop forever"
+ head: [Loop value: X]
+ body: [Loop value: X]
+#+END_SRC
+
+This must be rejected because no structural decrease exists. In Coq's
+Gallina this would have the type False, which breaks the logic system
+and falsifies it as a whole.
+
+* Higher-Order Relations
+
+Sol may support higher-order relations: relations that receive other
+relations as arguments.
+
+Example:
+
+#+BEGIN_SRC sol
+Query expression:
+ [Map relation: Increment source: XS target: YS]
+#+END_SRC
+
+However, unrestricted higher-order unification is not allowed in the
+total core. The following may be rejected or restricted:
+
+#+BEGIN_SRC sol
+Query expression:
+ [Map relation: P source: XS target: YS]
+#+END_SRC
+
+if =P= is an unconstrained relation variable and the system would need
+to synthesize arbitrary predicates.
+
+Higher-order relations must be governed by:
+
+- declared schemas;
+- capability restrictions;
+- totality certificates;
+- bounded search;
+- or parametricity constraints.
+
+* Primary Type System
+
+The primary type system of Sol is relational. Typing is enforced by
+proving relation membership.
+
+Example:
+
+#+BEGIN_SRC sol
+[Integer value: X]
+#+END_SRC
+
+is a type-like assertion:
+
+#+BEGIN_EXAMPLE
+X : Integer
+#+END_EXAMPLE
+
+But this is not a separate static annotation detached from the
+program. It is a relation in the same logical language.
+
+Similarly:
+
+#+BEGIN_SRC sol
+[Person id: P name: N age: A]
+#+END_SRC
+
+may constrain =P= to be a Person identifier (whatever domain it is),
+=N= to be Text, and =A= to be an Integer, according to the declared
+schema of =Person=.
+
+* Secondary Runtime Categories
+
+Sol may internally distinguish secondary runtime categories such as:
+
+- Query
+- Relation
+- DomainRelation
+- Rule
+- Variable
+- Literal
+- Constraint
+- Conjunction
+- Disjunction
+- SolverPlan
+
+These are implementation-level categories, rendering them not the
+primary semantic type system. The primary type system remains
+relational. This categorization serves to allow group operators, such
+as =:and= and =:or=.
+
+* Important Non-Goals
+
+Sol should not be:
+
+- a general-purpose imperative language,
+- an unrestricted Prolog,
+- a syntax skin over ordinary Turing-complete execution,
+- a language where every relation can accidentally enumerate its inhabitants,
+- a language where newline adjacency secretly means conjunction.
+
+* Summary
+
+Sol is a total relational language where:
+
+- relations are labeled propositions,
+- domains are unary relations,
+- typing is relation membership,
+- conjunction is explicit through =:and=,
+- joins happen by shared variables,
+- infinite domains constrain by default,
+- generation is explicit and controlled,
+- recursion is accepted only with a totality proof,
+- higher-order predicates are restricted,
+- and execution is proof search plus constraint solving.