Did you know ... | Search Documentation: |
SWI-Prolog future directions |
The introduction of new features and new incompatibilities with the ISO standard in SWI-Prolog version 7 has raised considerable concerns about the future of SWI-Prolog. This page addresses some of these issues. The page is organised as questions and answers.
With SWI-Prolog, we want to provide a language that satisfies the needs of academic and industrial application programmers. SWI-Prolog is a dialect of Prolog because we believe that the logic foundation provides a good basis for many relatively simple reasoning tasks seen in applications. Its reflective capabilities as well as its `program is data' view makes it an ideal platform for domain specific languages (DSLs) or micro languages, which allows for concise description of application knowledge and separation of this knowledge from how it is applied. And, of course, Prolog provides a safe environment, free of crashes and memory leaks.
SWI-Prolog does not want to be an implementation that solves the N-queens problems elegantly and in splendid isolation. Instead, we want it to be a system that can operate as a component in modern IT architectures. That is why it concentrates on multi threading, network communication (sockets, HTTP, TIPC) and exchange of commonly used structured documents (XML, JSON, RDF, CSV, etc.). That is also why it supports relevant data types: Unicode text, big integers, rational numbers and strings, as well as extended runtime detection of Prolog data types that allows for a natural representation of dynamic data while being able to distinguish a string from a list and the empty list from an identifier without additional type information in the form of declarations or wrapping data into terms.
With SWI-Prolog we want to maintain a living language. That means that we will try to make the language evolve with insights and trends in the IT world. Together with our aim to support application programming, this leads to the following priorities:
Not (much) more than it used to. If you are looking for a Prolog system
that restricts you to the ISO standard, SWI-Prolog should not be the
first thing to look at. ISO compliant programs that do not explore
corner cases such as relying on specific behaviour on basically invalid
programs (e.g., expecting length(42,X)
to fail silently) should run
fine.
The ISO standard has done a great job in synchronising and cleaning the syntax and core semantics of the language. However, the standardised core is too small to accommodate real applications, the process to enlarge is too slow (while some vendors do not even want to enlarge it) and there are no mechanisms that allow us to make even tiny incompatible changes needed to accommodate new features in a clean way. Especially this last restriction turns it into a practically dead language.
Below are a number of specific issues with the ISO standard that we experience as counterproductive.
ISO Prolog defines the behaviour of all built-in predicates both when operating on arguments within the meaningful domain for the predicate and when faced with illegal input, such as passing a non-list to the first argument of length/2. It often even defines the precise error that must be raised if the call is wrong for multiple reasons. We consider this counterproductive for the following reasons:
length(List, Len)
is true when Len is the number of
elements in the list List is easy. Defining that this predicate
is non-deterministic if List is a partial list and Len is unbound
is necessary. Defining what happens on length(List, -1)
is also
necessary, because this this can be a goal resulting from a sensible
program.
However, it makes little sense to define what happens on length(42,
Len)
. The ISO committee decided this must fail because it wanted
implementations to allow rewriting e.g., length(List,5)
into List =
[_,_,_,_,_]
and 42 = [_,_,_,_,_]
fails silently. These debates
are involved, trying to balance between usefulness of an exception,
performance costs and implementation effort to do the required
checking, possibilities for rewriting (as with length/2),
consistency, etc. There is no single truth here.
call((fail,1))
must raise a type_error. Here, SWI-Prolog complies
because call/1 compiles the argument before execution. Systems
that prefer an opportunistic approach however will execute fail/0
and never try to execute the invalid 1
.
The precise error and failure conditions make it
hard to perform program rewrites that now needs to maintain the
exact behaviour on invalid input. It also does not allow for
introducing exceptions in places where failure was prescribed
because the costs of generating an exception was deemed to be
too high by the ISO committee. It even disallows systems to reject
goals like Len is A+B, length(Len, List)
based on static analysis.
In the long run, we expect that SWI-Prolog will become a partially typed language. Type systems have to choose between decidability and expressiveness. Here, we plan to go for expressiveness by defining a type, mode and determinism annotation that can capture the richness of practical Prolog programming as we see it now. Based on that, we expect analysis tools that proof errors rather than correctness. Some of this is likely to be based on the Ciao assertion language.
Being a logic based and dynamically typed language, Prolog should offer
precise arithmetic results whenever possible. It should have unbound
integers and rational numbers at its core. Unbound integers are not
prescribed by the ISO standard and rational numbers are not even
mentioned. Arithmetic is defined almost as the C language defines it,
except that all overflow and evaluation errors must be mapped to
exceptions (a good idea). Typed languages have no choice but defining
that a specific operation returns a value of a specific type. Untyped
languages however can define that X**Y
evaluates to an integer if this
represents the exact result and a rational number or floating point
number otherwise. ISO decided for two exponentiation operators (**
and
^
), where ^
evaluates to to an integer and raises an exception if
the result is not integral. We find this confusing. If you want **
to
do floating point arithmetic, you can cast one of the arguments to
escape from the world of integers:
?- Exp is 2**float(2). Exp = 4.0
In the long run we expect a tighter integration of rational numbers. This will involve integral division to be mapped to rationals and might involve syntactical extensions to accommodate rationals.
ISO Prolog provides no sensible way to represent a string of characters.
In general, such data cannot be represented using atoms because systems
pose limits on the length of atoms, the characters that can be inside
atoms or the number of atoms or do not provide atom garbage collection.
There are two list representations for strings, one as a list of
character codes and one as a list of characters (atoms containing
exactly one character). Both representations are expensive and neither
can be distinguished at runtime from either a list of integers or a list
of atoms or the empty list. Without runtime type information on strings,
debugging becomes hard (should the debugger print "ab"
as is or as
[97,98]
?) and dynamic data structures cannot be created. The two
string representations suggest a choice, but in reality this choice
needs to be made for the whole application and is therefore not a real
choice.
The SWI-Prolog extensions fix some of these problems by reviving a string type as there was in the BSI Prolog standard and which survived in several implementations (e.g., ECLiPSe, Amzi!). We expect that YAP will follow. The primitives will be synchronised with ECLiPSe.
In the long run, we might do something about the _chars and _codes predicates, possibly by introducing a new data type char.
The ISO Prolog syntax has several flaws.
Unicode is there now long enough for SWI-Prolog to support the
widely accepted \uXXXX
and \UXXXXXXXX
. In addition, SWI-Prolog
supports quasi quotations,
which can support pretty looking long strings as well as safely
interpolate Prolog variables into source code fragments of
external languages.
array[index]
, X.member
, function()
or
function(Arg) { Body }
cannot be expressed in ISO Prolog. This
results in needlessly verbose and unnatural notations (see e.g.,
library(record)) and makes it hard to define DSLs with a natural
syntax.When introducing the extensions in version 7, several people have claimed that SWI-Prolog should choose a new name that does not refer to Prolog, such as Picat or Mercury did. Both languages share concepts with Prolog, but both differ so much that it is practically impossible to run programs unmodified on both a Prolog processor and either Picat or Mercury.
This is quite different for SWI-Prolog. Most `reasonable' programs that satisfy the ISO standard or where designed for (especially YAP or SICStus Prolog) run unmodified on SWI-Prolog or can be changed easily to run on multiple systems.
With SWI-Prolog we wish to maintain as good as possible compatibility with ISO and other Prolog implementations in the `close family' (notably YAP and SICStus and at somewhat larger distance Ciao, ECLiPSe and XSB), while adding extensions to the system that supports our guiding principles). In practice, this means that an application programmer who experiences problems running the same source on another Prolog system while this is not a priori impossible (for example because of completely different feature sets, such as the (un)availability of attributed variables) and there is no sensible work-around will be taken seriously.
YAP and SWI-Prolog have a similar drive, where YAP concentrates on performance and SWI-Prolog concentrates on development and stability. YAP uses many of SWI-Prolog's packages and generally copies features that are required to support these packages.
Within the ISO core, it is fairly cheap to switch or maintain a portable application to just about any Prolog. If ISO doesn't satisfy your requirements and you want to be able to switch, you should carefully examine the language features you need and which systems are capable to support these.
And, of course, SWI-Prolog is open source, so you are free to fork it under the conditions of the license.
SWI-Prolog has always been used extensively in education. The changes introduced in version 7 do not make it significantly less suitable for this purpose. There are two issues that might require some attention.
--traditional
= or use back quoted strings
as illustrated in the calls below:
?- phrase("hello", "hello world", R). false. ?- phrase(`hello`, `hello world`, R). R = [32, 119, 111, 114, 108, 100]. ?- phrase("hello", `hello world`, R). R = [32, 119, 111, 114, 108, 100].
.(A, .(B, []))
'[|]'
. This can be made visible using e.g. =../2,
but no longer using display/1 or write_canonical/1 which
always use the list syntax.
?- [H|T] =.. L. L = ['[|]', H, T].
In the long run we would like to establish comprehensive tutorial material for SWI-Prolog's extensions.
I would like to thank all people who constructively helped shaping SWI-Prolog's recent extensions and expressed their concerns about the directions taken.