Constraints-based extensions are highly experimental and under active development. Use of extensions other than the ones pertaining rational arithmetic is strongly discouraged. We refer to extension by constraint domains as Twelf(X), where X refers different domains.

Twelf(X) extensions allow Twelf to deal more efficiently with some specific domains (e.g. numbers). They do so by

- modifying type reconstruction to accommodate other equivalences beyond those entailed by traditional beta-eta-conversion;
- defining special types, on which proof search is performed using ad-hoc decision procedures rather than traditional depth-first strategy;
- adding countably many new symbols to the language, signifying all the elements of the domain.

- Installing an Extension: Making constraint domains available
- Equalities of Rational Numbers: Rationals with equality
- Inequalities over Rational Numbers: Rationals with equality and inequality
- Integer Constraints: Integers with equality and inequality
- Equalities over Strings: Strings and concatenation
- 32-bit Integers: Integers representable as string of 32 bits
- Sample Constraint Programs: Some examples of use
- Restrictions and Caveats: Alerts!

Extensions are installed using the declaration

%useextension name

For example,

%use equality/rationals.

loads the extension dealing with equality over the rationals. Typically,
an extension introduces new symbols in the signature. For example,
`equality/rationals`

adds a type for rational numbers:

rational : type.

In addition to these symbols, a countably infinite set of "special"
ones may be also accepted by the system as the result of loading one
extension. In our example, after loading `equality/rationals`

the
symbols

135 5/13 ~1/4

become valid constants of type `rational`

.

Finally, it is possible for an extension to be built on top of others,
and therefore to depend on them. Hence, loading an extension usually
causes all the others it depends upon to be loaded as well, if they have
not been already. For example, the extension `inequality/rationals`

requires `equality/rationals`

, and hence the declaration

%use inequality/rationals.

subsumes

%use equality/rationals.

Extensions must be installed prior to their use. For this reason, it is
a safe practice to put all the `%use`

declarations at the
beginning of the program.

As mentioned before, the extension presiding equality over the rational
numbers is called `equality/rationals`

, and it is therefore installed
by the declaration

%use equality/rationals.

This causes the declarations

rational : type. ~ : rational -> rational. %prefix 9999 ~. + : rational -> rational -> rational. %infix left 9997 +. - : rational -> rational -> rational. %infix left 9997 -. * : rational -> rational -> rational. %infix left 9998 *.

to be included in the current global signature.

Note that We do not add an equality predicate for rationals. This is unnecessary, since the extension modifies standard type checking so that arithmetic identities are taken into account. However, one can always define an equality predicate by declaring

== : rational -> rational -> type. %infix none 100 ==. id : X == X.

This extension is also responsible for defining special constants for all the rational numbers. These follow the syntax

<rational> ::= ~<unsigned> | <unsigned> <unsigned> ::= <digits> | <digits>/<digits> <digits> ::= 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | <digits> <digits>

It is important to notice the difference between `~ 10`

and
`~10`

. The former is the object obtained applying the unary minus
operator to the positive number *10*; the second stands for the number
*-10*. The difference is, however, just syntactical, since the former
is automatically evaluated into the latter by Twelf(X). In general, one
should keep in mind that Twelf(X) extensions do not modify the behavior
of the lexer; hence, for example, multiplication of a variable `X`

by two still needs to be written as `X * 2`

(note the spaces
preceding and following the multiplication symbol), while `X*2`

will be interpreted by the system as a single variable named
"`X*2`

".

Unification of arithmetic expressions is done by Gaussian elimination. Thus, unification problems that can be reduced to linear equations over existentially quantified variables are immediately solved; other problems not falling in this class are likely to be delayed as unificational constraints.

Arithmetical inequalities are handled by the extension
`inequality/rationals`

. This relies on `equality/rationals`

for the definition of rational number, so a declaration of

%use inequality/rationals.

implicitly entails one of

%use equality/rationals.

This extension adds the following to the signature:

> : rational -> rational -> type. %infix none 0 >. >= : rational -> rational -> type. %infix none 0 >=. +> : {Z:rational} X > Y -> (X + Z) > (Y + Z). +>= : {Z:rational} X >= Y -> (X + Z) >= (Y + Z). >>= : X > Y -> X >= Y. 0>=0 : 0 >= 0.

It also adds countably many proof objects such as

45>0 : 45 > 0.

witnessing that positive numbers are greater than zero.

Goals of the form

M > N or M >= N

are evaluated using a modified version of the simplex algorithm, rather than the usual proof-search mechanism. This will incrementally collect inequalities, assigning them incomplete (i.e. partially instantiated) proof objects, until either an inconsistency is discovered (generating failure) or they can be shown to be satisfied a unique solution (causing the proof objects to be finally completed).

The extensions `equality/integers`

and `inequality/integers`

deal with equalities and inequalities over the ring of integer numbers,
respectively. Since these two extensions are very similar to their
rationals counterparts, we will limit ourselves to outlining the
differences.

The signature introduced by `equality/integers`

resembles
`equality/rationals`

. The only difference lies in the name of
the main type:

integer : type. ~ : integer -> integer. %prefix 9999 ~. + : integer -> integer -> integer. %infix left 9997 +. - : integer -> integer -> integer. %infix left 9997 -. * : integer -> integer -> integer. %infix left 9998 *.

Like before, countably many special constants are added to the signature. They follow the syntax

<integer> ::= ~<digits> | <digits>

The extension `equality/integers`

takes advantage of the fact that (unlike the rationals) the integers are not a dense ordering to considerably shorten the set of symbols needed:

>= : integer -> integer -> type. %infix none 0 >=. +>= : {Z:integer} X >= Y -> (X + Z) >= (Y + Z).

It also declares countably many proof objects such as

37>=0 : 37 >= 0.

for all non-negative integers.

Notice that strict inequality `>`

can be easily defined in this case:

> : integer -> integer -> type. %infix none 0 >. >=> : X >= (Y + 1) -> X > Y.

For solving linear inequalities over the integers, we again use the simplex method, but we add special routines that implement branch-and-bound search. Specifically, inequalities are internally interpreted over rationals, and a check is performed regularly (whenever a new inequality is added) to ensure the rational solution space contains integral points.

Note that all known methods for solving systems of integral linear
inequations are notoriously inefficient. In the branch-and-bound method
we adopted, the number of branches to consider is potentially
exponential with respect to the size of the problem. We recommend using
the `inequality/rationals`

extension instead, whenever the situation
allows the two to be used interchangeably.

A third domain currently supported by the Twelf(X) extensions are strings of (printable) characters. The only operator provided is string concatenation. Installing

%use equality/strings.

causes the following signature to be loaded:

string : type. ++ : string -> string -> string. %infix right ++ 9999.

String constants are sequences of printable characters enclosed by double quotes:

"foobar" : string

Under these conventions, strings cannot therefore contain the double
quote character `"`

. Escape sequences, such as `"\n"`

have no
special meaning; moreover, we do not currently provide input/output
primitives.

Finally, it is required that string constants occupy a single line. The declaration

mystring : string = "foo bar".

is not considered syntactically correct.

Another supported domain are 32-bit integers. This domain is used mainly in Proof Carrying Code applications, and because of this, it has fairly different structure and features than the extension for (unrestricted) integers (see section 6.4 Integer Constraints). First of all, the algorithms used were kept short and simple, so that they can be easily read and verified to be correct. Secondly, the set of arithmetic operators provided has been kept to a minimum. Also, each of these is implemented as a type family instead of a function symbol, so that unification of arithmetic expressions follows the same rule as that of regular terms. Finally, for each arithmetic operator, we also provide a type family which, in addition to carry out the computation, also provides a proof object for it.

Declaring

%uses word32.

causes the following signature to be loaded into the system:

word32 : type. + : word32 -> word32 -> word32 -> type. * : word32 -> word32 -> word32 -> type. / : word32 -> word32 -> word32 -> type. prove+ : {X:word32} {Y:word32} {Z:word32} {P:+ X Y Z} type. proof+ : {X:word32} {Y:word32} {Z:word32} {P:+ X Y Z} prove+ X Y Z P. prove* : {X:word32} {Y:word32} {Z:word32} {P:* X Y Z} type. proof* : {X:word32} {Y:word32} {Z:word32} {P:* X Y Z} prove* X Y Z P. prove/ : {X:word32} {Y:word32} {Z:word32} {P:+ X Y Z} type. proof/ : {X:word32} {Y:word32} {Z:word32} {P:+ X Y Z} prove/ X Y Z P.

Goals involving `+`

and `*`

are immediately solved if at least
two of the arguments are ground objects (i.e. numbers), and delayed as
constraints otherwise. In particular

?- + 3 X 9.

is solved immediately and can be used to compute *9-3*.
Goals involving `/`

are delayed unless both the first and the second
argument are known. The type families `prove+`

, `prove*`

,
`prove/`

can be used to obtain proof object for the arithmetic
operation, and use them in the remaining part of the computation:

?- P : + 3 X 9. Solving... X = 6. P = 3+6. More? n ?- prove+ 3 X 9 P. Solving... P = 3+6; X = 6. More? n

It is important to stress that the domain modeled here is not the ring
of integers modulo 32 but rather the restriction of the integer ring to the
interval *0*...*4294967295*, so that for example the query:

?- + 1 X 0.

will not admit a solution.

Using Twelf(X), we can write a modified version of `append`

that
takes into account the size of the list involved:

%use equality/rationals. item : type. list : rational -> type. a : type. b : type. ... nil : list 0. cons : item -> list N -> list (N + 1). append : list M -> list N -> list (M + N). append_nil : append nil L L. append_cons : append (cons X L1) L2 (cons X L3) <- append L1 L2 L3.

Type checking the definition of `append`

requires some algebraic manipulation. For example, validity of `append_nil`

depends on the identity
*0+M=M*.

Most classic Constraint Logic Programming (CLP) examples found in the literature can be easily translated to Twelf(X). We present here a simple mortgage calculator:

%use inequality/rationals. %% equality == : rational -> rational -> type. %infix none 1000 ==. id : X == X. %% mortgage payments mortgage : rational -> rational -> rational -> rational -> rational -> type. m0 : mortgage P T I MP B <- T > 0 <- 1 >= T <- Interest == T * P * I * 1/1200 <- B == P + Interest - (T * MP). m1 : mortgage P T I MP B <- T > 1 <- MI == P * I * 1/1200 <- mortgage (P + MI - MP) (T - 1) I MP B.

This CLP program takes four parameters: the principal `P`

, the life
of the mortgage in months `T`

, the annual interest rate (%)
`I`

, the monthly payment `MP`

, and the outstanding balance
`B`

.

Finally, we use the string extensions to write a simple parser. Consider the following syntax for simple arithmetic expressions:

<expr> ::= <number> | <expr>+<expr> | <expr>-<expr> | <expr>*<expr> | (<expr>) <number> ::= <digit> | <digit><number> <digit> ::= 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9

This can be translated quite directly into Twelf by constructing parsing
predicates `digit`

, `number`

, `expression`

as follows:

digit : string -> type. d0 : digit "0". d1 : digit "1". d2 : digit "2". d3 : digit "3". d4 : digit "4". d5 : digit "5". d6 : digit "6". d7 : digit "7". d8 : digit "8". d9 : digit "9". number : string -> type. nd : number X <- digit X. n++ : number (X ++ Y) <- digit X <- number Y. expression : string -> type. en : expression X <- number X. e* : expression (X ++ "*" ++ Y) <- expression X <- expression Y. e+ : expression (X ++ "+" ++ Y) <- expression X <- expression Y. e- : expression (X ++ "-" ++ Y) <- expression X <- expression Y. ep : expression ("(" ++ X ++ ")") <- expression X.

To ensure the consistency of the calculus, use of types defined by Twelf(X) extensions is restricted. Specifically, we do not allow them to be used as dynamic assumptions. This rules out meaningless (under the current operating semantics) goals like

?- 0 > 1 -> foo.

as well as meaningful, but intractable ones, such as

?- {X : rational} X * X >= 0

One important thing to keep in mind when using arithmetic is that this
currently is defined over the rationals, rather than the integers or the
set of natural numbers. While in many applications this is of no
consequence, it might generate in some cases surprising results. While
it is certainly possible to define the characteristic function of the
integer subset (see the content of `clp-examples/integers/`

in the
distribution) and use this to enforce all computations to take place in
the intended domains, this introduces a big performance penalty and
should in general be avoided.

Go to the first, previous, next, last section, table of contents.