Language Reference/Terms

This section describes terms and how execution/evaluation of terms and clauses proceeds.

Semantically, there are two kinds of terms: formulas and expressions.


 * Expressions represent values, like the number 7.
 * Formulas represent logical statements, like "the number 7 is greater than the number 3".

Syntactically the two kinds have a huge overlap and therefore the syntax unites the two kinds into terms.

The following definition of  is simplified, in the sense that it includes syntactic constructions that are not legal. For example, one cannot legally write ! + !. We do however believe that using this simple syntax description in combination with intuitive understanding of language concepts, the type system, and the operator hierarchy described below is better for most purposes.

: (  )            <Cut> <Ellipsis> <FactvariableAssignment>

Backtracking
The evaluation of a Prolog program is a search for a "solution" to the goal. Each step in the search for a solution can either succeed or fail. At certain points in the program execution there are more than one possible choices for finding a solution. When such a choice point is met a so called backtrack point is created. A backtrack point is a recording of the program state plus a pointer to the choice that was not executed. If it turn out that the original choice could not provide the solution (i.e. if it fails), then the program will backtrack to the recorded backtrack point. Thereby restoring the program state and pursuing the other choice. The mechanism will be described and exemplified in details in the following sections.

Literals
Literals have.

<Literal>: <IntegerLiteral> <RealLiteral> <CharacterLiteral> <StringLiteral> <BinaryLiteral> <ListLiteral> <CompoundDomainLiteral>

See also

Variables
Variables in Visual Prolog are immutable: once they are bound to a value they retain that value, but backtracking can unbind the variable again during the process of restoring a previous program state.

A variable can thus be bound (during unification and matching), if it is already bound then it evaluates to the value that it is bound to.

Variables are names starting with an upper-case letter or with an underscore (_), followed by a sequence of letters (both uppercase and lowercase), digits, and underscore characters (all in all called an UppercaseIdentifier):

<Variable>: <UppercaseIdentifer>

The following are examples of valid variable names:

My_first_correct_variable_name _ _Sales_10_11_86

while the next two are invalid:

1stattempt second_attempt

The variable consisting of single underscore character (i.e. _</vp>) is known as the anonymous variable. The anonymous variable is used in patterns and bindings where the corresponding value is of no interest and should be ignored. Every occurrence of the anonymous variable is an independent anonymous variable, i.e. even though the anonymous variable is used several times in a single clause they have no relation to each other.

If variables that starts with an underscore are not anonymous, but they are still intended for values of no interest that should be ignored. The compiler will issue a warning if the value of such a warning is actually not ignored.

Prolog variables are local to the clause in which it occurs. That is, if two clauses each contain a variable called X</vp>, these X</vp>-s are two distinct variables.

A variable is said to be free when it is not yet associated with a term and to be bound or instantiated when it is unified with a term.

The Visual Prolog compiler does not make a distinction between upper and lower case letters in names, except for the first letter. This means that the two variables SourceCode</vp> and SOURCECODE</vp> are the same.

Identifier
<Identifier>: <MemberName> <GlobalScopeMembername> <ScopeQualifiedMemberName>

<MemberName>: <LowerCaseIdentifier>

Identifiers are used to refer to named entities (i.e. classes, interfaces, constants, domains, predicates, facts, ...).

An identifier can just be a lower case identifier (i.e. a lowercase letter followed by a sequence of letters, numbers and underscore characters).

Many entities can have the same name. So it may be necessary or desirable to qualify the lowercase identifier the name of the particular scope of interest, or to state that the name is in the global namespace.

Global Entities Access
The only global entities, which exist in Visual Prolog, are built-in domains, predicates, and constants. Global names are directly accessible in any scope. There might however exist situations where a global name is shadowed by a local or imported name. In that case the global entity can be qualified with a double colon '::</vp>' (without a prefixed class/interface name). The double colon can be used everywhere, but the most important place is where an interface name is used as formal parameter type specifier.

<GlobalScopeMemberName>: :: <MemberName>

Class/Interface Member Access
Static members of classes and interfaces are accessed by means of qualification with the class name (and optionally a namespace prefix):

<ScopeQualifiedMemberName> <NamespacePrefix>-opt <ScopeName> :: <MemberName>

<NamespacePrefix>: <NamespaceIdentifier>-opt \

<ScopeName>: <LowercaseIdentifier>

The ScopeName is the name of the class or interface that defines/declares the name.

Namespace prefixing is explained in:.

Some names can be accessed without qualification, see.

Predicate Call
A predicate call have the form

<PredicateCall>: <Term> ( <Term>-comma-sep-list-opt )

The first term must be an expression that evaluates to a value with predicate type. Typically, it is either the name of a predicate in a class, or an expression that evaluates to a predicate member of an object.

Notice that some predicates return values, whereas other predicates do not. A predicate that returns a value is an expression, and the predicate call is often referred to as a function call. A predicate that does return a value is a formula.

A predicate is invoked by applying arguments to the predicate. The predicate must have a flow-pattern that matches the free/bound state of the arguments.

Most predicates are defined by a set of clauses, but some predicates are built into the language and some are defined externally in a DLL (perhaps in a foreign programming language).

When a predicate is invoked by a predicate call, each clause is executed in turn until one of them succeeds, or there are no more clauses left to execute. If no clause succeeds the predicate fails.

If a clause succeeds and there are more relevant clauses left, a backtrackpoint is created to the next relevant clause.

Thus, a predicate can fail, succeed, and even succeed multiple times.

Each clause has a head and optionally a body.

When a predicate is called the clauses are tried in turn (from top to bottom). For each clause the arguments in the head is unified with the arguments from the call. If this unification succeeds then the body of the clause (if present) is executed. The clause succeeds, if the match of the head succeeds and the body succeeds. Otherwise it fails.

Unification
When a predicate is called the arguments from the call is unified with the terms in the head of each clause.

Unification is the process of binding variables in such a way that two terms become equal, making as few bindings as possible (i.e. leaving as much as possible open for further binding).

Variables can be bound to any kind of terms, including variables or terms containing variables.

Unification is either possible or impossible, i.e. it can succeed or fail.

Variables and terms to which they are unified have types, a variable can only be bound to a term of the same type as the variable, or a subtype. When two variables are bound to each other they must therefore have exactly the same type.

Unification takes place (as mentioned) between a predicate call and the clause head. It also takes place when two terms are compared for equality.

In the example above T1</vp> could have been a predicate call and T2</vp> a clause head. But they could also have been two terms that were compared with equal "=</vp>".

Matching
Matching is the same as unification except that variables can only be bound to grounded terms. A grounded term is a term that does not contain any unbound variables.

It is the flow-patterns that are stated for predicates, that make it possible to use matching rather than full-blown unification.

Nested Function Calls
Terms that have to be unified or matched with each other are allowed to contain sub-terms that are actually expressions or function calls that have to be evaluated before the unification/matching can be completed.

The evaluation of such sub-terms is done on a by-need basis.

In a predicate call all input arguments are evaluated before the predicate is called, all output arguments are variables, which does not need evaluation.

Clause heads can also contain terms that have to be evaluated, before matching/unification can be determined.


 * all matching/unification that does not require any evaluation is performed before any evaluation is performed;
 * then evaluation corresponding to input arguments is performed one by one left-to-right. Comparing each value to the corresponding input after each evaluation;
 * then the clause body is evaluated;
 * then the output arguments are evaluated (left-to-right);
 * then the return value (if the predicate is a function) is evaluated.

If any of these fail then the rest of the evaluation is not carried out.

All in all the base principles are:


 * input after other match, before body evaluation
 * output after body evaluation
 * left-to-right

Fact Variable Assignment
Assign operator :=</vp> is used to assign a new value for a <FactVariable>. The <Term> must be evaluated to a value of suitable type (i.e. the same type as the fact variable, or a subtype).

<FactVariableAssignment>: <FactVariable> := <Term>

Facts
A fact database contains a number of fully instantiated (grounded) predicate heads corresponding to the facts from the facts section declaration. The facts can be accessed by a predicate call, using the fact name as the predicate name. The predicate call is matched against each fact in turn; succeeding with a possible backtrack point to the next fact each time the predicate call match the fact. When there are no more facts in the fact database then the predicate call fails.

New facts can be asserted using the predicates, , and. is the same as and it asserts a new fact to the end of the list of facts, whereas  asserts a new fact to the start of the list.

Existing facts can be retracted with the predicate and. retracts the first fact that match the argument binding variables in the argument and leaving a backtrack point so that more facts will potentially be retracted when backtracking.

retracts all facts that matches the arguments and succeeds without any binding.

Operators
Operators are organized in a precedence hierarchy. In the rule below operators in each group have same precedence, which is higher than those below. I.e. the power operator has higher precedence than unary minus and plus, which in turn has higher precedence than the multiplication operators, etc. Parenthesis can be used to circumvent the precedence (and for clarification).

<Operator>: one of   <PowerOperator> <UnaryOperator> <MultiplicationOperator> <AdditionOperator> <OtherwiseOperator> <RelationOperator> <MustUnifyOperator> <InOperator> <AndOperator> <OrOperator>

<UnaryOperator>: one of   - +

All operators except the <UnaryOperator> 's are binary. The power operator is right associative, all other operators are left associative.

<RelationOperator>, <MustUnifyOperator> and <InOperator> have same precedence.

Notice that the placement <UnaryOperator> is not consistent with mathematics, where these operators are at the same level as the <AdditionalOperator> 's. The difference has no influence of the calculated value, but it allows writing 2*-2</vp>, where mathematics would require a parenthesis around the second operator 2*(-2)</vp>. It also means that -2*2</vp> is mmeans (-2)*2 where it would be -(2*2)</vp> in mathematics (the resulting value is the same).

Arithmetic Operators
The arithmetic operators are used for arithmetic operations on numbers. They are expressions, which takes expressions as arguments. They have root types as arguments and return universal types as result. (See .)

<PowerOperator>: ^

<MultiplicationOperator>: one of   * / div mod quot rem

<AdditionOperator>: one of   +  -

Relational Operators
The relational operators are formulas, which takes expressions as arguments. Given this nature they are non-associative.

<RelationOperator>: one of =   >   <   >=   <=   <>   ><

First the left term is evaluated, then the right term is evaluated and then the results are compared.

Notice that <></vp> (different) is not the dual operation of = (equal). <></vp> compares two values, whereas <vp>=</vp> tries to unify two terms (in the general case at least).

The dual to expression <vp>A = B</vp> is <vp>not (A = B)</vp>.

Must Unify Operator
The must unify operator is a procedure, which takes expressions as arguments. It is non-associative.

<MustUnifyOperator>: ==

A == B unifies A and B ; if the unification fails an exception is raised, otherwise the predicate succeeds. Therefore A == B always succeeds.

Bitwise and boolean operators
The following operators for bitwise operations on <vp>unsigned</vp>, <vp>unsigned64</vp> and <vp>unsignedNative</vp>.

A ** B % A and B A ++ B % A or B A -- B % A and not B A ^^ B % A exclusive or B A % not A A << N % Shifts the bits in A N times to the left. A >> N % Shifts the bits in A N times to the right.

The logical operations (<vp>**</vp>, <vp>++</vp>, <vp>^^</vp> and <vp></vp>) can also be used on <vp>boolean</vp> values.

The shift operations discard bits that is shifted out of the number, and shift-in zero bits in the opposite end.

Logical Operators
The <AndOperator> (s) and <OrOperator> (s) are formulas, which takes formulas as arguments. They are all left associative. The <vp>,</vp> and <vp>and </vp> are synonyms and so are <vp>; </vp> and <vp>or</vp>.

<AndOperator>: one of,  and

<OrOperator>: one of ;  or orelse

and
The evaluation of an <vp>and</vp> term <vp>A, B</vp> proceeds as follows. First the left sub-term <vp>A</vp> is evaluated. If this evaluation fails, the whole <vp>and</vp> term fails. If <vp>A</vp> succeeds then the right sub-term <vp>B</vp> is evaluated. If this evaluation fails, the whole <vp>and</vp> term fails, otherwise the <vp>and</vp> term succeeds.

Thus the second sub-term <vp>B</vp> is only evaluated, if the first sub-term <vp>A</vp> succeeds.

or
The evaluation of an <vp>or</vp> term <vp>A</vp>; <vp>B</vp> proceeds as follows. First a backtrack point to the second term <vp>B</vp> is created and then the first term <vp>A</vp> is evaluated. If the evaluation of the first term succeeds, then the whole <vp>or</vp> term succeeds and is left with a backtrack to the second term <vp>B</vp>. If the evaluation of the first term fails, the backtrack point to the second term is activated.

If the backtrack point to the second term <vp>B</vp> is activated (either because the first term fails, or because something later in the execution invokes the backtrack point), then the second term <vp>B</vp> is evaluated and the whole <vp>or</vp> term will succeed if <vp>B</vp> succeeds.

Thus an <vp>or</vp> term can succeed with a backtrack point and the second sub-term <vp>B</vp> is only evaluated on backtrack.

Using parentheses <vp>or</vp> can be nested deeply in clauses.

clauses p(X) = Y :- (X = 1, !, Z = 3 or Z = 7), Y = 2*Z.

We recommend careful usage of <vp>or</vp>. It is mainly intended for usage in test-conditions:

clauses isOutside(X) :- (X < 10 or X > 90), !.

<vp>or</vp> is a nondeterministic construction, but <vp>orelse</vp> can be used as a deterministic pendant:

clauses isOutside(X) :- X < 10 orelse X > 90.

orelse
<vp>orelse</vp> is a deterministic pendant to the nondeterministic <vp>or</vp>. <vp>A orelse B</vp> will succeed if <vp>A</vp> succeeds or if <vp>B</vp> succeeds, but it will not leave a backtrack point to <vp>B</vp> if <vp>A</vp> succeeds.

The evaluation of an <vp>orelse</vp> term <vp>A orelse B</vp> proceeds as follows: First a backtrack point to the second term <vp>B</vp> is created and then the first term <vp>A</vp> is evaluated. If the evaluation of the first term succeeds then the backtrack to the second term (and any backtrack point within it) <vp>B</vp> are removed again and the whole <vp>orelse</vp> term succeeds. If the evaluation of the first term <vp>A</vp> fails, the backtrack point to the second term <vp>B</vp> is evaluated.

So an <vp>orelse</vp> term does not leave a backtrack point.

otherwise
<vp>otherwise</vp> is an expression operator; though it has control flow that makes it resemble the logical operators.

A otherwise B

is an expression (<vp>A</vp> and <vp>B</vp> must be expressions). If the evaluation of <vp>A</vp> succeeds by evaluating to the value VA then <vp>A otherwise B</vp> evaluates to VA, otherwise (i.e. if the evaluation of <vp>A</vp> fails) then <vp>A otherwise B</vp> will be the result of evaluating <vp>B</vp>.

<vp>otherwise</vp> is right associative:

A otherwise B otherwise C => A otherwise (B otherwise C)

It has lower precedence than all other expression operators, but higher than relational operators:

V < A + tryGet otherwise 9 => V < ((A + tryGet) otherwise 9)

<vp>core</vp> have been enriched with a predicate <vp>isSome</vp> for providing default values for <vp>core::optional</vp> matching:

not
The takes a term as the argument. The evaluation of <vp>not(A)</vp> first evaluates <vp>A</vp>. If <vp>A</vp> succeeds, then <vp>not(A)</vp> fails, if <vp>A</vp> fails, then <vp>not(A)</vp> succeeds.

Notice that <vp>not(A)</vp> will never bind any variables, because if <vp>not(A)</vp> succeeds then <vp>A</vp> has failed, and a failed term does not bind anything. If <vp>not(A)</vp> on the other hand fails, it cannot bind any variables either, because then the term itself failed.

Also notice that <vp>not(A)</vp> can never succeed with backtrack points, because if <vp>not(A)</vp> succeeds then <vp>A</vp> have failed, and a failed term cannot contain any backtrack points. This in turn means that all possibilities of success in <vp>A</vp> have been exhausted.

cut (!)
Cut "<vp>!</vp>" removes all backtrack points created since the entrance to the current predicate, this means all backtrack points to subsequent clauses, plus backtrack points in predicate calls made in the current clause before the "<vp>!</vp>".

<Cut>: !

cut Scopes
A cut scope is a scope to which the effect of a <vp>cut</vp> is limited. Meaning that if a <vp>cut</vp> is met within a cut scope then only backtrack points within that scope are discarded, while backtrack points outside (i.e. prior to) the cut scope remains.

The clauses of a predicate is a cut scope. Meeting a <vp>cut</vp> will (at most) discard the backtrack points that was created after entrance to the predicate. Backtrack points created before entrance to the predicate will remain.

Several terms introduce cut scopes (see the respective terms:, , ). Here we will use <vp>if-then-else</vp> to illustrate the effect of cut scopes. Consider the schematic <vp>if-then-else</vp> term:

if Cond then T1 else T2 end if

The condition <vp>Cond</vp> is a cut-scope, meaning that a <vp>cut</vp> inside <vp>Cond</vp> will only have effect inside <vp>Cond</vp>. <vp>Cut</vp>s inside <vp>T1</vp> and <vp>T2</vp>, on the other hand, have effect outside the <vp>if-then-else</vp> statement.

Consider this code fragment:

X = getMember_nd([3,1,2]), if X = getMember_nd([3,3]), ! then write(X) else ! end if, fail

<vp>getMember_nd</vp> is a nondeterministic predicate. The evaluation of this code will go as follows. First <vp>X</vp> is bound to <vp>3</vp> and <vp>getMember_nd</vp> leaves a backtrack point (so that <vp>X</vp> can later become <vp>1</vp> and then even <vp>2</vp>).

Then we evaluate the condition in the <vp>if-then-else</vp> term. The first part of this condition succeeds as <vp>3</vp> is a member of <vp>[3,3]</vp>. The first part also leaves a backtrack point, so that it can be examined whether <vp>X</vp> is a member several times.

Now we meet a <vp>cut</vp>. This <vp>cut</vp> is inside the condition part of an <vp>if-then-else</vp> statement, so it only has local effect, meaning that it only discards the backtrack point in the second <vp>getMember_nd</vp>, but leaves the backtrack point in the first <vp>getMember_nd</vp> predicate.

The whole condition succeeds and we enter the then-part and write out "<vp>3</vp>".

After the <vp>if-then-else</vp> we meet <vp>fail</vp>, which backtracks us to the first <vp>getMember_nd</vp>.

<vp>getMember_nd</vp> then binds <vp>X</vp> to <vp>1</vp>, and leaves a backtrack point (so that <vp>X</vp> can later become <vp>2</vp>).

Then we evaluate the condition in the <vp>if-then-else</vp> term. The first part of this condition fails as <vp>1</vp> is not a member of <vp>[3,3]</vp>. So we enter the <vp>else</vp>-part.

Here we meet a <vp>cut</vp>. This <vp>cut</vp> is in the <vp>else</vp>-part of a conditional term so it has effect outside the <vp>if-then-else</vp> term and subsequently it discards the backtrack point in the first <vp>getMember_nd</vp>.

When we meet the <vp>fail</vp> after the <vp>if-then-else</vp> term there are no more backtrack points in the code and it will fail. So all in all <vp>X</vp> never becomes <vp>2</vp>.

fail/0 and succeed/0
and are two built-in nullary predicates. always fails and always succeeds, besides this the predicates have no effect.

List Comprehension
<ListComprehensionTerm> : [ <Term> || <Term> ]

The list comprehension term is a list expression. Consider this schematic term:

[ Exp || Gen ]

<vp>Gen</vp> is (typically) a <vp>nondeterm</vp> term. <vp>Exp</vp> is evaluated for each solution of <vp>Gen</vp>, and the resulting <vp>Exp</vp>'s are collected in a list. The <vp>Exp</vp> corresponding to the first solution of <vp>Gen</vp> is the first element in the list, etc. This list is the result of the list comprehension term. <vp>Exp</vp> must be procedure (or erroneous). Both <vp>Exp</vp> and <vp>Gen</vp> are.

The list comprehension (normally) reads: The list of <vp>Exp</vp>'s such that <vp>Gen</vp>.

Object Member Access
Whenever we have a reference to an object, we can access the object member predicates of that object. <MemberAccess>: <Term> : <Identifier>

(Currently, the term must be a variable or a fact variable).

The must have the type of the term.

Inside an implementation object member predicates can be invoked without reference to an object, because "<vp>This</vp>" is subsumed, see.

Domain, Functor, and Constant Access
Domains, functors, and constants are all accessed as if they are class members. Even if they are declared in an interface. This means that when they are qualified, then they are always qualified with class/interface name and a double colon.