Skip to content
Lexical Syntax

Lexical Syntax

Whitespace and Indentation

Rel is a free-form language. You can use whitespace anywhere, except within identifiers, symbols, numbers, and keywords. See Identifiers and Keywords and Symbols.

Unlike in some programming languages such as Python, indentation does not play a significant role in Rel.

You are encouraged to follow one of the styles featured in the examples shown in the documentation. If you use a radically different style, others may find it difficult to read what you wrote.


Rel uses /* ... */ for block (multiline) comments and // ... for end-of-line comments.


Identifier := ("^")? IdCharInit IdChar*
IdCharInit := [a-zA--ωΑ-Ω_]
IdChar     := [a-zA--ωΑ-Ω_0-9]

An identifier is a sequence of characters that begins with a Unicode letter, an underscore or a caret (^). The first character can be followed by zero or more Unicode letters, underscores, or numbers.

For example, valid identifiers are: x, a1, b1c, θ, φ, Σ, ß, β1, β2, and ^V.

Rel identifiers are case sensitive: ab, Ab, aB, and AB are four different identifiers.

The optional caret character ^ can appear only at the beginning of an identifier. Identifiers beginning with a caret are used for naming some relations that are automatically generated by Rel. See Value Types and Entities. It is best to avoid using such identifiers for other purposes.

Due to missing features in the parser generator, the definition explicitly lists supported ranges of Unicode letters (hence the Greek ranges). This is currently incomplete, so Rel does not yet support other Unicode letters in identifiers.

Some identifiers are keywords, that is, they are reserved for signifying various constructs in the language. All other identifiers can be used to name relations and variables.

The first letter of a variable is important. First-order variables must begin with a lower-case letter, and higher-order variables must begin with an upper-case letter. See Higher-Order Definitions for more information.

Symbols (RelNames)

Symbol := ":" Identifier

A Symbol has the form of an identifier prefixed with a colon. The term “Symbol” begins with an upper-case “S”, to distinguish it from the usual meaning of the word “symbol”. For example, + is a symbol, but :name is a Symbol.

A Symbol represents itself, that is, it is a literal. It cannot be used to name a relation or a variable.

A Symbol is sometimes called a RelName. The term “RelName” is an abbreviation of “relation name.” You can use Symbols to tag the representations of relations embedded in modules. But this is not the only application of Symbols. You can also use Symbols, for instance, to represent units of measurement in value types.

A Symbol is a specialized form of a string. See Specialization for more information.

Symbols are often combined with identifiers, as in person:address:city. Such a combination is often called a qualified name and can be used like an identifier. This is just a convenient form of a partial relational application: person[:address, :city] in this case.

When you replace a qualified name with a partial relational application, you may have to enclose the latter in parentheses, because the composition operator . binds more strongly than partial relational application. See Precedence for more information.

To check whether the value of a variable is a Symbol, you can use the Library function RelName. You can also convert the result to a string by using the Library function: relname_string or despecialize.

You can form a Symbol directly from a string literal, even if the string is not an identifier:

// read query
def output[:"a b"] = :"c d"

Notice, however, that string interpolation is not allowed in a string literal that is used to form a Symbol in this manner.

If the strings are not literals, but are extracted from a relation, you can form the corresponding Symbols by using the specialization operator #:

// read query
def p = 1; 2
def q = "a%p"; "b%p"
def output = #(q)

Infix Symbols

You can use infix symbols for relation names, where the relation represents an operation that can be written in an infix notation (opens in a new tab) with the operator (for example: +) placed between the arguments. For instance, the expression 1+2 is the infix notation for (+)[1, 2], which is a partial application equivalent to the expression x: (+)(1, 2, x).

You can define custom infix notations using the following infix symbols: , , , , , , , , , , , , and .

For example:

@inline def ()(a, b) = a + 1 = b
def output = 1  2

The infix used in alglib (Unicode 8764) is not the same character as your keyboard’s ~ (Unicode 126).

These symbols can also be useful as higher-order relational arguments, as this example from alglib shows:

def unary_relation(D, ) =
    equal(arity[], 1)

Next: Declarations

Was this doc helpful?