University of Amsterdam

Dept. of Social Science Informatics (SWI) Roeterstraat 15, 1018 WB Amsterdam The Netherlands Tel. (+31) 20 5256786

SWI-Prolog 2.1

Reference Manual

Updated for version 2.1.4, August 1995

Jan Wielemaker

jan@swi.psy.uva.nl

SWI-Prolog is a Prolog implementation based on a subset of the WAM (Warren Abstract Machine [Warren, 1983]). SWI-Prolog has been designed and implemented such that it can easily be modified for experiments with logic programming and the relation between logic programming and other programming paradigms (such as the object oriented XPCE environment [Anjewierden & Wielemaker, 1989]). SWI-Prolog has a rich set of built-in predicates and reasonable performance, which makes it possible to develop substantial applications in it. The current version offers a module system, garbage collection and an interface to the C language.

This document gives an overview of the features, system limits and built-in predicates.

Copyright \begin{matrix}c \\ ◯ \end{matrix} 1990–1995, Jan Wielemaker

Contents

1 Introduction 1 1.1 SWI-Prolog . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1 1.2 Status . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2 1.3 Should you be Using SWI-Prolog? . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2 1.4 Graphics . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3 1.5 Version 1.5 Release Notes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3 1.6 Version 1.6 Release Notes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3 1.7 Version 1.7 Release Notes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4 1.8 Version 1.8 Release Notes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4 1.9 Version 1.9 Release Notes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4 1.10 Version 2.0 Release Notes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4 1.11 Version 2.1 Release Notes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5 1.12 Acknowledgements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6

2 Overview 7

2.1 Starting SWI-Prolog from the Unix Shell . . . . . . . . . . . . . . . . . . . . . . . . 7

2.1.1 Command Line Options . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 7 2.2 GNU Emacs Interface . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9 2.3 Online Help . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9 2.4 Query Substitutions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10

2.4.1 Limitations of the History System . . . . . . . . . . . . . . . . . . . . . . . . 10 2.5 Reuse of toplevel bindings . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10 2.6 Overview of the Debugger . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12 2.7 Compilation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15 2.8 Environment Control . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15 2.9 Saved States . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17

2.9.1 Types of Saved States and Portability . . . . . . . . . . . . . . . . . . . . . . 17 2.9.2 Save Predicates . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17

2.10 Automatic loading of libraries . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19

2.10.1 Notes on Automatic Loading . . . . . . . . . . . . . . . . . . . . . . . . . . . 20 2.11 Garbage Collection . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20 2.12 Syntax Notes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21 2.13 System Limits . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21

2.13.1 Limits on Memory Areas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21 2.13.2 Other Limits . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21 2.13.3 Reserved Names . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23

CONTENTS 2.1

3 Built-In Predicates 25 3.1 Notation of Predicate Descriptions . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25 3.2 Consulting Prolog Source files . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25

3.2.1 Quick Load Files . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28 3.3 Listing Predicates and Editor Interface . . . . . . . . . . . . . . . . . . . . . . . . . . 29 3.4 Verify Type of a Term . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30 3.5 Comparison and Unification or Terms . . . . . . . . . . . . . . . . . . . . . . . . . . 30

3.5.1 Standard Order of Terms . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30 3.6 Control Predicates . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31 3.7 Meta-Call Predicates . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33 3.8 Advanced control-structures: blocks . . . . . . . . . . . . . . . . . . . . . . . . . . . 33 3.9 Grammar rule interface (phrase) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34 3.10 Database . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35

3.10.1 Indexing databases . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37 3.11 Declaring Properties of Predicates . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37 3.12 Examining the Program . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38 3.13 Input and Output . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 40

3.13.1 Input and Output Using Implicit Source and Destination . . . . . . . . . . . 40 3.13.2 Explicit Input and Output Streams . . . . . . . . . . . . . . . . . . . . . . . . 42 3.13.3 Switching Between Implicit and Explicit I/O . . . . . . . . . . . . . . . . . . 42

3.14 Status of Input and Output Streams . . . . . . . . . . . . . . . . . . . . . . . . . . . 43 3.15 Primitive Character Input and Output . . . . . . . . . . . . . . . . . . . . . . . . . . 44 3.16 Term Reading and Writing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 45 3.17 Analysing and Constructing Terms . . . . . . . . . . . . . . . . . . . . . . . . . . . . 46 3.18 Analysing and Constructing Atoms . . . . . . . . . . . . . . . . . . . . . . . . . . . . 48 3.19 Representing Text in Strings . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 49 3.20 Operators . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 50 3.21 Arithmetic . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 51 3.22 Arithmetic Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 51 3.23 Adding Arithmetic Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 54 3.24 List Manipulation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 54 3.25 Set Manipulation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 56 3.26 Sorting Lists . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 56 3.27 Finding all Solutions to a Goal . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 56 3.28 Invoking Predicates on all Members of a List . . . . . . . . . . . . . . . . . . . . . . 57 3.29 Forall . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 58 3.30 Formatted Write . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 58

3.30.1 Writef . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 58 3.30.2 Format . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 59 3.30.3 Programming Format . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 61

3.31 Terminal Control . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 62 3.32 Unix Interaction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 62 3.33 File System Interaction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 63 3.34 User Toplevel Manipulation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 64 3.35 Creating a Protocol of the User Interaction . . . . . . . . . . . . . . . . . . . . . . . 65 3.36 Debugging and Tracing Programs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 65 3.37 Obtaining Runtime Statistics . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 67 3.38 Finding Performance Bottlenecks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 68 3.39 Memory Management . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 69 3.40 Windows DDE interface . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 70

3.40.1 DDE client interface . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 70 3.40.2 DDE server mode . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 71

3.41 Miscellaneous . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 72 4 Using Modules 75

4.1 Why Using Modules? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 75 4.2 Name-based versus Predicate-based Modules . . . . . . . . . . . . . . . . . . . . . . 75 4.3 Defining a Module . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 76 4.4 Importing Predicates into a Module . . . . . . . . . . . . . . . . . . . . . . . . . . . 77

4.4.1 Reserved Modules . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 77 4.5 Using the Module System . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 78

4.5.1 Object Oriented Programming . . . . . . . . . . . . . . . . . . . . . . . . . . 78 4.6 Meta-Predicates in Modules . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 79

4.6.1 Definition and Context Module . . . . . . . . . . . . . . . . . . . . . . . . . . 80 4.6.2 Overruling Module Boundaries . . . . . . . . . . . . . . . . . . . . . . . . . . 80

4.7 Dynamic Modules . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 81 4.8 Module Handling Predicates . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 81 4.9 Compatibility of the Module System . . . . . . . . . . . . . . . . . . . . . . . . . . . 82

5 Foreign Language Interface 85 5.1 Overview of the Interface . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 85 5.2 Linking Foreign Modules . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 86

5.2.1 What linking is provided? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 86 5.2.2 What kind of loading should I be using? . . . . . . . . . . . . . . . . . . . . . 86 5.2.3 Static Linking . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 87 5.2.4 Dynamic Linking based on load foreign/[2,5] . . . . . . . . . . . . . . . . 89

5.3 Dynamic Linking of shared libraries . . . . . . . . . . . . . . . . . . . . . . . . . . . 90 5.4 Using the library shlib for .DLL and .so files . . . . . . . . . . . . . . . . . . . . . . . 90 5.5 Interface Data types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 92 5.6 The Foreign Include File . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 92

5.6.1 Argument Passing and Control . . . . . . . . . . . . . . . . . . . . . . . . . . 92 5.6.2 Analysing Terms via the Foreign Interface . . . . . . . . . . . . . . . . . . . . 94 5.6.3 Instantiating and Constructing Terms . . . . . . . . . . . . . . . . . . . . . . 96 5.6.4 Interaction with the garbage collector and stack-shifter . . . . . . . . . . . . . 98 5.6.5 Calling Prolog from C . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 99 5.6.6 Discarding Data . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 99 5.6.7 Calls based on predicate references . . . . . . . . . . . . . . . . . . . . . . . . 99 5.6.8 Foreign Code and Modules . . . . . . . . . . . . . . . . . . . . . . . . . . . . 101 5.6.9 Catching Signals (Software Interrupts) . . . . . . . . . . . . . . . . . . . . . . 102 5.6.10 Errors and warnings . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 102 5.6.11 Environment Control from Foreign Code . . . . . . . . . . . . . . . . . . . . . 102 5.6.12 Querying Prolog . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 102 5.6.13 Registering Foreign Predicates . . . . . . . . . . . . . . . . . . . . . . . . . . 103 5.6.14 Foreign Code Hooks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 104 5.6.15 Embedding SWI-Prolog in a C-program . . . . . . . . . . . . . . . . . . . . . 104

5.7 Example of Using the Foreign Interface . . . . . . . . . . . . . . . . . . . . . . . . . 106 5.7.1 C-Source file (lowercase.c) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 106 5.7.2 Compiling and Loading Foreign Code . . . . . . . . . . . . . . . . . . . . . . 107

5.8 Notes on Using Foreign Code . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 107 5.8.1 Garbage Collection and Foreign Code . . . . . . . . . . . . . . . . . . . . . . 107 5.8.2 Memory Allocation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 107 5.8.3 Debugging Foreign Code . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 107 5.8.4 Name Conflicts in C modules . . . . . . . . . . . . . . . . . . . . . . . . . . . 108 5.8.5 Compatibility of the Foreign Interface . . . . . . . . . . . . . . . . . . . . . . 108 6 Generating Runtime Applications 109

6.1 Limitations of qsave program . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 111 6.2 Runtimes and Foreign Code . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 111 6.3 Finding Application files . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 112 6.4 Using chpl for Configuration Information . . . . . . . . . . . . . . . . . . . . . . . . 113

6.4.1 Changing the emulator of a runtime application . . . . . . . . . . . . . . . . . 113 6.4.2 Passing a path to the application . . . . . . . . . . . . . . . . . . . . . . . . . 113

6.5 The Runtime Environment . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 114 6.5.1 The Runtime Emulator . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 114

A Hackers corner 117 A.1 Examining the Environment Stack . . . . . . . . . . . . . . . . . . . . . . . . . . . . 117 A.2 Intercepting the Tracer . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 117 A.3 Exception Handling . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 119

B Summary 121 B.1 Predicates . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 121 B.2 Artihmetic Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 129 B.3 Operators . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 129

Index

!/0, 32
!/1, 34
*/2, 52
+/2, 52
,/2, 32
-/1, 52
-/2, 52
->/2, 32
./2, 52

.so files, 86

///2, 52
//2, 52
/\/2, 53
;/2, 32
</2, 51
<</2, 53
=../2, 47
=/2, 31
=:=/2, 51
=</2, 51
==/2, 31
=@=/2, 31
=\=/2, 51
>/2, 51
>=/2, 51
>>/2, 53
@</2, 31
@=</2, 31
@>/2, 31
@>=/2, 31
\+/1, 32
\//2, 53
\/1, 53
\=/2, 31
\==/2, 31
\=@=/2, 31
^/2, 53
|/2, 32
abolish/2, 35
abort/0, 65
abs/1, 52

                                             absolute_file_name/2, 63
                                             absolute_file_name/3, 64
                                             access_file/2, 63
                                             acos/1, 53
                                             append/1, 41
                                             append/3, 55
                                             apply/2, 33
                                             apropos/1, 9
                                             arg/3, 47
                                             arithmetic_function/1, 54
                                             asin/1, 53
                                             assert/1, 35
                                             assert/2, 36
                                             asserta/1, 35
                                             asserta/2, 36
                                             assertz/1, 35
                                             assertz/2, 36
                                             at_halt/1, 28
                                             at_initialization/1, 28
                                             atan/1, 53
                                             atan/2, 53
                                             atom/1, 30
                                             atom_char/2, 48
                                             atom_chars/2, 48
                                             atom_length/2, 49
                                             atom_to_term/3, 49
                                             atomic/1, 30
                                             autoload/0, 110
                                             bagof/3, 57
                                             between/3, 51
                                             block/3, 34
                                             break/0, 64
                                             call/1, 33
                                             call_shared_object_function/2, 90
                                             ceil/1, 53
                                             character_count/2, 43
                                             chdir/1, 64
                                             checklist/2, 58

chpl, 110

                                             clause/2, 39

\underline{INDEX 2.1}

clause/3, 40
clause_property/2, 40
close/1, 42
close_dde_conversation/1, 71
close_shared_object/1, 90
compiling/0, 28
compound/1, 30
concat/3, 49
concat_atom/2, 49
consult/1, 25
context_module/1, 81
convert_time/8, 63
copy_term/2, 48
cos/1, 53
cputime/0, 54
current_arithmetic_function/1, 54
current_atom/1, 38
current_flag/1, 38
current_foreign_library/2, 91
current_functor/1, 38
current_input/1, 43
current_key/1, 38
current_op/3, 50
current_output/1, 43
current_predicate/2, 38
current_stream/3, 42
dde_current_connection/2, 72
dde_current_service/2, 72
dde_execute/2, 71
dde_register_service/2, 71
dde_request/3, 71
dde_unregister_service/1, 72
debug/0, 66
debugging/0, 66
delete/3, 55
delete_file/1, 63
discontiguous/1, 37
display/1, 45
display/2, 45
displayq/1, 45
displayq/2, 45

dlopen, 86

dwim_match/2, 72
dwim_match/3, 72
dwim_predicate/2, 39
dynamic/1, 37
e/0, 54
ed/0, 29
ed/1, 29

                                             edit/0, 29
                                             edit/1, 29

Emacs, 9

                                             ensure_loaded/1, 26
                                             erase/1, 36

exception-handling, 33

                                             exception/3, 119
                                             exists_directory/1, 63
                                             exists_file/1, 63
                                             exit/2, 34
                                             exp/1, 53
                                             expand_file_name/2, 64
                                             expand_term/2, 27
                                             explain/1, 9
                                             explain/2, 9
                                             export/1, 81
                                             export_list/2, 82
                                             fail/0, 32
                                             fail/1, 34
                                             feature/2, 16
                                             file_base_name/2, 63
                                             file_directory_name/2, 63
                                             file_search_path/2, 26
                                             fileerrors/2, 43
                                             findall/3, 56
                                             flag/3, 36
                                             flatten/2, 55
                                             float/1, 30
                                             floor/1, 52
                                             flush/0, 44
                                             flush_output/1, 44
                                             forall/2, 58
                                             foreign_file/1, 90
                                             format/1, 59
                                             format/2, 59
                                             format_predicate/2, 61
                                             free_variables/2, 47
                                             functor/3, 46
                                             garbage_collect/0, 69
                                             gensym/2, 72
                                             get/1, 44
                                             get/2, 44
                                             get0/1, 44
                                             get0/2, 44
                                             get_single_char/1, 45
                                             get_time/1, 62
                                             getenv/2, 62

GNU-Emacs, 9

                                             ground/1, 30

halt/0, 65
halt/1, 65
hash_term/2, 37
help/0, 9
help/1, 9
history_depth/1, 46
ignore/1, 33
import/1, 77
index/1, 37
initialization/1, 28
int_to_atom/2, 49
int_to_atom/3, 48
integer/1, 30, 52
intersection/3, 56
is/2, 51
is_absolute_file_name/1, 64
is_list/1, 54
is_set/1, 56
keysort/2, 56
last/2, 55
leash/1, 66
length/2, 55
library_directory/1, 26
limit_stack/2, 69
line_count/2, 43
line_position/2, 43
list_to_set/2, 56
listing/0, 29
listing/1, 29
load_foreign/2, 89, 90
load_foreign_library/1, 91
load_foreign_library/2, 91
log/1, 53
log10/1, 53
make/0, 26
make_library_index/1, 20
maplist/3, 58
max/2, 52
member/2, 55
memberchk/2, 55
merge/3, 55
merge_set/3, 56
min/2, 52
mod/2, 52
module/2, 81
module_transparent/1, 81
msort/2, 56
multifile/1, 37

                                             name/2, 48
                                             nl/0, 44
                                             nl/1, 44
                                             nodebug/0, 66
                                             nonvar/1, 30
                                             noprotocol/0, 65
                                             nospy/1, 66
                                             nospyall/0, 66
                                             not/1, 33
                                             notrace/0, 66
                                             nth0/3, 55
                                             nth1/3, 55
                                             nth_clause/3, 40
                                             number/1, 30
                                             number_chars/2, 48
                                             numbervars/4, 47
                                             once/1, 33
                                             op/3, 50
                                             open/3, 42
                                             open_dde_conversation/3, 71
                                             open_null_stream/1, 42
                                             open_shared_object/2, 90
                                             phrase/2, 34
                                             phrase/3, 34
                                             pi/0, 54
                                             PL_abort_hook(), 104
                                             PL_abort_unhook(), 104
                                             PL_action(), 102
                                             PL_arg(), 96
                                             PL_atom_value(), 95
                                             PL_atomic(), 95
                                             PL_bktrk(), 99
                                             PL_call(), 99
                                             PL_call_predicate(), 100
                                             PL_context(), 101
                                             PL_dispatch_hook(), 104
                                             PL_fail(), 92
                                             PL_fatal_error(), 102
                                             PL_float_value(), 95
                                             PL_foreign_context(), 93
                                             PL_foreign_control(), 93
                                             PL_functor(), 95
                                             PL_functor_arity(), 96
                                             PL_functor_name(), 96
                                             PL_halt(), 105
                                             PL_initialise(), 105
                                             PL_integer_value(), 95
                                             PL_is_atom(), 95
                                             PL_is_float(), 95

PL_is_int(), 95
PL_is_string(), 95
PL_is_term(), 95
PL_is_var(), 95
PL_lock(), 98
PL_mark(), 99
PL_module_name(), 102
PL_new_atom(), 96
PL_new_float(), 96
PL_new_functor(), 96
PL_new_integer(), 96
PL_new_module(), 102
PL_new_string(), 96
PL_new_term(), 96
PL_predicate(), 99
PL_predicate_arity(), 100
PL_predicate_functor(), 100
PL_predicate_module(), 101
PL_predicate_name(), 100
PL_query(), 102
PL_register_foreign(), 103
PL_reinit_hook(), 104
PL_reinit_unhook(), 104
PL_retry(), 93
PL_signal(), 102
PL_string_value(), 95
PL_strip_module(), 101
PL_succeed(), 92
PL_toplevel(), 105
PL_type(), 94
PL_unify(), 98
PL_unify_atomic(), 98
PL_unify_functor(), 98
PL_unlock(), 98
PL_warning(), 102
please/3, 15
plus/3, 51
portray/1, 45
portray_clause/1, 30
predicate_property/2, 38
predsort/3, 56
preprocessor/2, 28
print/1, 45
print/2, 45
profile/3, 68
profile_count/3, 69
profiler/2, 69
prolog/0, 65
prolog_current_frame/1, 117
prolog_frame_attribute/3, 117
prolog_load_context/2, 27

                                             prolog_skip_level/2, 118
                                             prolog_to_os_filename/2, 64
                                             prolog_trace_interception/3, 117
                                             prompt/2, 46
                                             proper_list/1, 55
                                             protocol/1, 65
                                             protocola/1, 65
                                             protocolling/1, 65
                                             put/1, 44
                                             put/2, 44
                                             qcompile/1, 28
                                             qload/1, 29
                                             qsave_program/1, 110
                                             qsave_program/2, 109
                                             random/1, 52
                                             read/1, 46
                                             read/2, 46
                                             read_clause/1, 46
                                             read_clause/2, 46
                                             read_history/6, 46
                                             read_link/3, 64
                                             read_variables/2, 46
                                             read_variables/3, 46
                                             recorda/2, 36
                                             recorda/3, 36
                                             recorded/2, 36
                                             recorded/3, 36
                                             recordz/2, 36
                                             recordz/3, 36
                                             redefine_system_predicate/1, 35
                                             rename_file/2, 63
                                             repeat/0, 32
                                             require/1, 26
                                             reset_profiler/0, 69
                                             restore/1, 19
                                             retract/1, 35
                                             retractall/1, 35
                                             reverse/2, 55
                                             same_file/2, 63
                                             save/1, 18
                                             save/2, 19
                                             save_program/1, 18
                                             save_program/2, 17
                                             see/1, 41
                                             seeing/1, 41
                                             seen/0, 42
                                             select/3, 55
                                             set_feature/2, 17
                                             set_input/1, 43

set_output/1, 43
set_tty/2, 62
setarg/3, 47
setenv/2, 62
setof/3, 57
sformat/2, 61
sformat/3, 61
shell/0, 62
shell/1, 62
shell/2, 62
show_profile/1, 68
sin/1, 53
size_file/2, 63
skip/1, 44
skip/2, 44
sleep/1, 73
sort/2, 56
source_file/1, 27
source_file/2, 27
source_location/2, 27
spy/1, 66
sqrt/1, 53
stack_parameter/4, 70
statistics/0, 67
statistics/2, 67
stream_position/3, 42
string/1, 30
string_length/2, 49
string_to_atom/2, 49
string_to_list/2, 49
style_check/1, 67
sublist/3, 58
subset/2, 56
substring/4, 50
subtract/3, 56
succ/2, 51
swritef/2, 59
swritef/3, 59
tab/1, 44
tab/2, 44
tan/1, 53
tell/1, 41
telling/1, 41
term_expansion/2, 27
term_to_atom/2, 49
time/1, 67
time_file/2, 63
tmp_file/2, 64
told/0, 42
trace/0, 65

                                             trace/1, 66
                                             trace/2, 66
                                             tracing/0, 66
                                             trim_stacks/0, 69
                                             true/0, 32
                                             tty_get_capability/3, 62
                                             tty_goto/2, 62
                                             tty_put/2, 62
                                             ttyflush/0, 44
                                             union/3, 56
                                             unknown/2, 67
                                             unload_foreign_library/1, 91
                                             unsetenv/1, 62
                                             use_module/1, 77
                                             use_module/2, 77
                                             var/1, 30
                                             visible/1, 66
                                             volatile/1, 111
                                             wait_for_input/3, 43
                                             wildcard_match/2, 72

Win32s, 4

                                             write/1, 45
                                             write/2, 45
                                             write_ln/1, 58
                                             writef/1, 58
                                             writef/2, 58
                                             writeq/1, 45
                                             writeq/2, 45
                                             xor/2, 53

– xii –

Chapter 1

Introduction

1.1 SWI-Prolog

SWI-Prolog has been designed and implemented to get a Prolog implementation which can be used for experiments with logic programming and the relation to other programming paradigms. The intention was to build a Prolog environment which offers enough power and flexibility to write substantial applications, but is straightforward enough to be modified for experiments with debugging, optimisation or the introduction of non-standard data types. Performance optimisation is limited due to the main objectives: portability (SWI-Prolog is entirely written in C and Prolog) and modifiability.

SWI-Prolog is based on a very restricted form of the WAM (Warren Abstract Machine) described in [Bowen & Byrd, 1983] which defines only 7 instructions. Prolog can easily be compiled into this language and the abstract machine code is easily decompiled back into Prolog. As it is also possible to wire a standard 4-port debugger in the WAM interpreter there is no need for a distinction between compiled and interpreted code. Besides simplifying the design of the Prolog system itself this approach has advantages for program development: the compiler is simple and fast, the user does not have to decide in advance whether debugging is required and the system only runs slightly slower when in debug mode. The price we have to pay is some performance degradation (taking out the debugger from the WAM interpreter improves performance by about 20%) and somewhat additional memory usage to help the decompiler and debugger.

SWI-Prolog extends the minimal set of instructions described in [Bowen & Byrd, 1983] to improve performance. While extending this set care has been taken to maintain the advantages of decompilation and tracing of compiled code. The extensions include specialised instructions for unification, predicate invocation, some frequently used built-in predicates, arithmetic, and control (;/2, |/2), if-then (->/2) and not (\+/1).

This manual does not describe the full syntax and semantics of SWI-Prolog, nor how one should write a program in Prolog. These subjects have been described extensively in the literature. See [Bratko, 1986], [Sterling & Shapiro, 1986], and [Clocksin & Mellish, 1981]. For more advanced Prolog material see [O’Keefe, 1990]. Syntax and standard operator declarations confirm to the ‘Edinburgh standard’. Most built in predicates are compatible with those described in [Clocksin & Mellish, 1981]. SWI-Prolog also offers a number of primitive predicates compatible with Quintus Prolog^{1}, [Qui, 1987] and BIM Prolog^{2} [BIM, 1989].

1Quintus is a trademark of Quintus Computer Systems Inc., USA

2BIM is a trademark of BIM sa/nv., Belgium

CHAPTER 1. INTRODUCTION 2.1

1.2 Status

This manual describes version 2.1 of SWI-Prolog. SWI-Prolog has been used now for several years. The application range includes Prolog course material, meta-interpreters, simulation of parallel Prolog, learning systems, natural language processing and two large workbenches for knowledge engineering. Although we experienced rather obvious and critical bugs can remain unnoticed for a remarkable long period, we can assume the basic Prolog system is fairly stable. Bugs can be expected in unfrequently used builtin predicates.

Some bugs are known to the author. They are described as footnotes in this manual.

1.3 Should you be Using SWI-Prolog?

There are a number of reasons why you better choose a commercial Prolog system, or another academic product:

• SWI-Prolog is not supported Although I usually fix bugs shortly after a bug report arrives, I cannot promise anything. Now that the sources are provided, you can always dig into them yourself.

• Memory requirements and performance are your first concerns A number of commercial compilers are more keen on memory and performance than SWI-Prolog. I do not wish to offer some of the nice features of the system, nor its portability to compete on raw performance.

• You need features not offered by SWI-Prolog In this case you may wish to give me suggestions for extensions. If you have great plans, please contact me (you might have to implement them yourself however).

On the other hand, SWI-Prolog offers some nice facilities:

• Nice environment This includes ‘Do What I Mean’, automatic completion of atom names, history mechanism and a tracer that operates on single key-strokes. Interfaces to standard Unix editors are provided, as well as a facility to maintain programs (see make/0).

• Very fast compiler The compiler handles about 100K bytes per second on a SPARC-II processor.

• Transparent compiled code SWI-Prolog compiled code can be treated just as interpreted code: you can list it, trace it, assert to or retract from it, etc. This implies you do not have to decide beforehand whether a module should be loaded for debugging or not. Also, performance is much better than the performance of most interpreters.

• Profiling SWI-Prolog offers tools for performance analysis, which can be very useful to optimise programs. Unless you are very familiar with Prolog and Prolog performance considerations this might be more helpful than a better compiler without these facilities.

• Flexibility SWI-Prolog allows for easy and flexible integration with C, both Prolog calling C functions as C calling Prolog predicates. SWI-Prolog is provided in source form, which implies SWI-Prolog can be linked in with another package. Command line options and predicates to obtain information from the system and feedback into the system are provided.

• Integration with PCE SWI-Prolog offers a tight integration to the Object Oriented Package for User Interface Development, called PCE [Anjewierden & Wielemaker, 1989]. PCE is now also available for the X Window System.

1.4 Graphics

SWI-Prolog has no provisions for graphical applications itself. The standard graphical environment to be used with SWI-Prolog is XPCE. XPCE/SWI-Prolog provides an interactive graphical develpment platform that is portable over many Unix/X11 implementations as well as MS-Windows (3.1) and Windows-NT (3.5).

XPCE is a licenced product. A fully functional free demo version for PC/Linux is available from

ftp://swi.psy.uva.nl/pub/xpce/linux, for more information see URL
     http://www.swi.psy.uva.nl/projects/xpce/home.html

or contact xpce-request@swi.psy.uva.nl.

1.5 Version 1.5 Release Notes

There are not many changes between version 1.4 and 1.5. The C-sources have been cleaned and comments have been updated. The stack memory management based on using the MMU has been changed to run on a number of System-V Unix systems offering shared memory. Handling dates has been changed. All functions handling dates now return a floating point number, expressing the time in seconds since January 1, 1970. A predicate convert time/8 is available to get the year, month, etc. The predicate time/6 has been deleted. get time/1 and convert time/8 together do the same.

From version 1.5, the system is distributed in source form, rather than in object form as used with previous releases. This allows users to port SWI-Prolog to new machines, extend and improve the system. If you want your changes to be incorporated in the next release, please indicate all changes using a C-preprocessor flag and send complete source files back to me. Difference listings are of no use, as I generally won’t have exactly the same version around.

1.6 Version 1.6 Release Notes

Version 1.6 is completely compatible with version 1.5. Some new features have been added, the system has been ported to various new platforms and there is a provisional interface to GNU-Emacs. This interface will be improved and documented later.

The WAM virtual-machine interpreter has been modified to use GCC-2’s support for threaded code.

From version 1.6, the sources are now versioned using the CVS version control system.

1.7 Version 1.7 Release Notes

Version 1.7 intergrates the GNU-readline library, offering powerful history and command-line editing both using EMACS and vi key-bindings.

1.8 Version 1.8 Release Notes

Version 1.8 offers a stack-shifter to provide dynamically expanding stacks on machines that do not offer operating-system support for implementing dynamic stacks.

1.9 Version 1.9 Release Notes

Version 1.9 offers better portability including an MS-Windows 3.1 version. Changes to the Prolog system include:

• Redefinition of system predicates Redefinition of system predicates was allowed silently in older versions. Version 1.9 only allows it if the new definition is headed by a :- redefine system predicate/1 directive.

• ‘Answer’ reuse The toplevel maintains a table of bindings returned by toplevel goals and allows for reuse of these bindings by prefixing the variables with the $ sign. See section 2.5.

• Better sourcecode administration Allows for proper updating of multifile predicates and finding the sources of individual clauses.

1.10 Version 2.0 Release Notes

Version 2.0 is first of all a freeze of all the features added to the various 1.9.x releases. Version 2.0.6 for PC has moved from the WATCOM C 32-bit windows extender to Windows-NT and runs under Windows 3.1 using the Win32s NT emulator.

New features offered:

• 32-bit Virtual Machine Removes various limits and improves performance.

• Inline foreign functions ‘Simple’ foreign predicates no longer build a Prolog stack-frame, but are directly called from the VM. Notably provides a speedup for the test predicates such as var/1, etc.

• Various compatibility improvements • Stream based I/O library

All SWI-Prolog’s I/O is now handled by the stream-package defined in the foreign include file <SWI-Stream.h>. Physical I/O of Prolog streams may be redefined through the foreign language interface, facilating much simpler integration in window environments.

Version 2.0.6 offers a few incompatibilities:

• retractall/1

In previous releases, the definition of retractall/1 was:

    retractall(Term) :-
            retract(Term),
            fail.
    retractall(_).

As from version 2.0.6, retractall/1 is implemented as a deterministic foreign predicate compatible with Quintus Prolog. It behaves as:

    retractall(Head) :-
            retract(Head),
            fail.
    retractall(Head) :-
            retract((Head :- _)),
            fail.
    retractall(_).

I.e. the definition behaves the same when handling predicates consisting of facts. Clauses with a non-true body will be retracted if their head matches.

• Foreign interface types All foreign interface types now have names ending in t to lessen the chance for conflicts. term, atomic, functor and module have #define’s for backward compatibility.

• PL register foreign()

The attributes is now a bitwise or of the attribute flags rather than a 0 terminated list. This has no consequences for predicates that have no attributes (99% of them), while predicates with just one attribute will generate a compiler warning, but work properly otherwise. Predicates with more than one attributes must be changed.

• PL dispatch events This pointer is replaced by PL dispatch hook(). A function was necessary for the Windows-NT .DLL interface.

1.11 Version 2.1 Release Notes

In addition to several bugfixes, the 2.1 versions provide some new features:

• setarg/3

A new predicate setarg/3 for extra-logical (destructiveZ) assignment to arguments of terms is provided.

   • Modified keysort/2

keysort/2 is now stable with regard to multiple values on the same key. Makes this predicate compatible with SICStus and Quintus.

• Modified grammar rule expansion DCG translation of free variables now calls phrase/3, which has been changed slightly to deal with ‘un-parsing’. Modification is probably not complete, but it fixes some problems encountered by Michael Böhlen.

• Exception handling The top of the runtime stack are automatically dumped on floating point exceptions.

• Foreign interface Added facilities to allow for embedding SWI-Prolog in C applications.

1.12 Acknowledgements

Some small parts of the Prolog code of SWI-Prolog are modified versions of the corresponding Edinburgh C-Prolog code: grammar rule compilation and writef/2. Also some of the C-code originates from C-Prolog: finding the path of the currently running executable and the code underlying absolute file name/2. Ideas on programming style and techniques originate from C-Prolog and Richard O’Keefe’s thief editor. An important source of inspiration are the programming techniques introduced by Anjo Anjewierden in PCE version 1 and 2.

I also would like to thank those who had the fade of using the early versions of this system, suggested extensions or reported bugs. Among them are Anjo Anjewierden, Huub Knops, Bob Wielinga, Wouter Jansweijer, Luc Peerdeman, Eric Nombden, Frank van Harmelen, Bert Rengel.

Martin Jansche (jansche@novell1.gs.uni-heidelberg.de) has been so kind to reorganise the sources for version 2.1.3 of this manual.

Overview

2.1 Starting SWI-Prolog from the Unix Shell

It is advised to install SWI-Prolog as ‘pl’ in the local binary directory. SWI-Prolog can then be started from the Unix shell by typing ‘pl’. The system will boot from the system’s default boot file, perform the necessary initialisations and then enter the interactive top level.

After the necessary system initialisation the system consults (see consult/1) the user’s initialisation file. This initialisation file should be named ‘verb.plrc’^{1} and reside either in the current directory or in the user’s home directory. If both exist the initialisation file from the current directory is loaded. The name of the initialisation file can be changed with the ‘-f file’ option. After loading the initialisation file SWI-Prolog executes a user initialisation goal. The default goal is a system predicate that prints the banner message. The default can be modified with the ‘-g goal’ option. Next the toplevel goal is started. Default is the interactive Prolog loop (see prolog/0). The user can overwrite this default with the ‘-t toplevel’ option.

2.1.1 Command Line Options

The full set of command line options is given below:

     -help

When given as the only option, it summarises the most important options.

     -v

When given as the only option, it summarises the version and the architecture identifier.

     -Lsize

Give local stack size in K bytes (200 K default). Note that there is no space between the size option and its argument. For machines with dynamic stack allocation this flag sets the maximum value to which the stack is allowed to grow (2 Mbytes default). A maximum is useful to stop buggy programs from claiming all memory resources. -L0 sets the limit to the highest possible value.

     -Gsize

Give global stack size in K bytes (100 K default). For machines with dynamic stack allocation the default is 4 Mbytes. See -L for more details.

1Windows: ‘ plrc’ as files cannot be named ‘.plrc’.

CHAPTER 2. OVERVIEW 2.1

-Tsize

Give trail stack size in K bytes (50 K default). For machines with dynamic stack allocation the default is 4 Mbytes. See -L for more details.

-Asize

Give argument stack size in K bytes (5 K default). For machines with dynamic stack allocation the default is 1 Mbytes. See -L for more details.

-c file ...

Compile files into an ‘intermediate code file’. See section 2.7.

-o output

Used in combination with -c or -b to determine output file for compilation.

-O

Optimised compilation. See please/3.

-f file

Use file as initialisation file instead of ‘.plrc’. ‘-f none’ stops SWI-Prolog from searching for an initialisation file.

-g goal

Goal is executed just before entering the top level. Default is a predicate which prints the welcome message. The welcome message can thus be suppressed by giving -g true. goal can be a complex term. In this case quotes are normally needed to protect it from being expanded by the Unix shell.

-t goal

Use goal as interactive toplevel instead of the default goal prolog/0. goal can be a complex term. If the toplevel goal succeeds SWI-Prolog exits with status 0. If it fails the exit status is 1. This flag also determines the goal started by break/0 and abort/0. If you want to stop the user from entering interactive mode start the application with ‘-g goal’ and give ‘halt’ as toplevel.

+/-tty

Switches tty control (using ioctl(2)) on (+tty) or off (-tty). Normally tty control is switched on. This default depends on the installation. You may wish to switch tty control off if Prolog is used from an editor such as Emacs. If switched off get single char/1 and the tracer will wait for a return.

-x bootfile

Boot from bootfile instead of the system’s default boot file. A bootfile is a file resulting from a Prolog compilation using the -b or -c option or a program saved

using qsave program/[1,2].
-r restorefile

Restore a state created by save program/[1,2] or save/[1,2] using the newstyle saved-states. Equivalent to restore(restorefile) from Prolog.

-p alias=path1[path2 ... ]

Define a path alias for file search path. alias is the name of the alias, path1 ... is a : separated list of values for the alias. A value is either a term of the form alias(value) or pathname. The computed aliases are added to file search path/2 using asserta/1, so they preceed predefined values for the alias. See file search path/2 for details on using this file-location mechanism.

--

Stops scanning for more arguments, so you can pass arguments for your application after this one.

The following options are for system maintenance. They are given for reference only.

-b initfile ...  -c file ...

Boot compilation. initfile ... are compiled by the C-written bootstrap compiler,

file ... by the normal Prolog compiler. System maintenance only.

     -d level

Set debug level to level. System maintenance only.

2.2 GNU Emacs Interface

A provisional interface to GNU-Emacs has been included since version 1.6 of SWI-Prolog. The interface is based on the freely distributed interface delivered with Quintus Prolog. When running Prolog as an inferior process under GNU-Emacs, there is support for finding predicate definitions, completing atoms, finding the locations of compilation-warnings and many more. For details, see

the files pl/lisp/README and pl/lisp/swi-prolog.el.

2.3 Online Help

Online help provides a fast lookup and browsing facility to this manual. The online manual can show predicate definitions as well as entire sections of the manual.

help Equivalent to help(help/1).

help(+What)

Show specified part of the manual. What is one of:

Name/Arity give help on specified predicate

Name give help on named predicate with any arity or C interface

function with that name

Section display specified section. section numbers are dashseparated numbers: 2-3 refers to section 2.3 of the manual. Section numbers are obtained using apropos/1.

Examples

?- help(assert).  give help on predicate assert
?- help(3-4).  display section 3.4 of the manual
?- help('PL retry'). give help on interface function PL retry()

apropos(+Pattern)

Display all predicates, functions and sections that have Pattern in their name or summary description. Lowercase letters in Pattern also match a corresponding uppercase letter. Example:

?- apropos(file). Display predicates, functions and sections that have ‘file’ (or ‘File’, etc.) in their summary description.

explain(+ToExplain)

Give an explanation on the given ‘object’. The argument may be any Prolog data object. If the argument is an atom, a term of the form Name/Arity or a term of the form Module:Name/Arity, explain will try to explain the predicate as well as possible references to it.

explain(+ToExplain, -Explanation)

Unify Explanation with an explanation for ToExplain. Backtracing yields further explanations.

2.4 Query Substitutions

SWI-Prolog offers a query substitution mechanism similar to that of Unix csh (csh(1)), called ‘history’. It allows the user to compose new queries from those typed before and remembered by the system. It also allows to correct queries and syntax errors. SWI-Prolog does not offer the Unix csh capabilities to include arguments. This is omitted as it is unclear how the first, second, etc. argument should be defined.^{2}

The available history commands are shown in table 2.1. Figure 2.1 gives some examples.

!!.  Repeat last query
!nr.  Repeat query numbered <nr>
!str.  Repeat last query starting with <str>
!?str.  Repeat last query holding <str>
^old^new.  Substitute <old> into <new> of last query
!nr^old^new.  Substitute in query numbered <nr>
!str^old^new. Substitute in query starting with <str>
!?str^old^new. Substitute in query holding <str>
h.  Show history list
!h.  Show this list

Table 2.1: History commands

2.4.1 Limitations of the History System

When in top level SWI-Prolog reads the user’s queries using history read/6 rather than read/1. This predicate first reads the current input stream up to a full stop. While doing so it maps all contiguous blank space onto a single space and deletes /* ... */ and % ... <cr> comments. Parts between double quotes (”) or single quotes (') are left unaltered. Note that a Prolog full stop consists of a ‘non-symbol’ character, followed by a period (.), followed by a blank character. ‘Symbol’ characters are: #$&*+-./:<=>?@^`~. A single quote immediately preceded by a digit (0-9) is considered part of the <digit>'<digit>... (e.g. 2'101; binary number 101) sequence.

After this initial parsing the result is first checked for the special ^old^new. construction. If this fails the string is checked for all occurrences of the !, followed by a !, ?, a digit, a letter or an underscore. These special sequences are analysed and the appropriate substitution from the history list is made.

From the above it follows that it is hard or impossible to correct quotation with single or double quotes, comment delimiters and spacing.

2.5 Reuse of toplevel bindings

Bindings resulting from the successfull execution of a toplevel goal are asserted in a database. These values may be reused in further toplevel queries as $Var. Only the latest binding is available. Example:

2One could choose words, defining words as a sequence of alpha-numeric characters and the word separators as anything else, but one could also choose Prolog arguments

/u4/staff/jan/.plrc consulted, 0.066667 seconds, 591 bytes
Welcome to SWI-Prolog (version 2.1.3, July 1995)
Copyright (c) 1990-1995, University of Amsterdam. All rights reserved.
1 ?- append("Hello ", "World", L).
L = [72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100]
Yes
2 ?- !!, writef('L = %s\n', [L]).
append("Hello ", "World", L), writef('L = %s\n', [L]).
L = Hello World
L = [72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100]
Yes
3 ?- sublist(integer, [3, f, 3.4], L).
L = [3]
Yes
4 ?- ^integer^number.
sublist(number, [3, f, 3.4], L).
L = [3, 3.400000]
Yes
5 ?- h.
    1   append("Hello ", "World", L).
    2   append("Hello ", "World", L), writef('L = %s\n', [L]).
    3   sublist(integer, [3, f, 3.4], L).
    4   sublist(number, [3, f, 3.4], L).
5 ?- !2^World^Universe.
append("Hello ", "Universe", L), writef('L = %s\n', [L]).
L = Hello Universe
L = [72, 101, 108, 108, 111, 32, 85, 110, 105, 118, 101, 114, 115, 101]
Yes
6 ?- halt.

Figure 2.1: Some examples of the history facility

     1 ?- maplist(plus(1), "hello", X).
     X = [105,102,109,109,112]
     2 ?- format('~s~n', [$X]).
     ifmmp

Figure 2.2: Reusing toplevel bindings

Note that variables may be set by executing =/2:

     6 ?- X = statistics.
     X = statistics
     7 ?- $X.
     28.00 seconds cpu time for 183,128 inferences
     4,016 atoms, 1,904 functors, 2,042 predicates, 52 modules
     55,915 byte codes; 11,239 external references
                           Limit    Allocated       In use
     Heap         :                                624,820 Bytes
     Local  stack :    2,048,000        8,192          404 Bytes
     Global stack :    4,096,000       16,384          968 Bytes
     Trail  stack :    4,096,000        8,192          432 Bytes

2.6 Overview of the Debugger

SWI-Prolog has a standard 4-port tracer [Clocksin & Mellish, 1981] with an optional fifth port. This fifth port, called unify allows the user to inspect the result after unification of the head. The ports are called call, exit, redo, fail and unify. The tracer is started by the trace/0 command, when a spy point is reached and the system is in debugging mode (see spy/1 and debug/1) or when an error is detected at run time. Note that in the interactive toplevel goal trace/0 means “trace the next query”. The tracer shows the port, displaying the port name, the current depth of the recursion and the goal. The goal is printed using the Prolog predicate print/1 (default), write/1 or display/1. An example using all five ports is shown in figure 2.3.

On leashed ports (set with the predicate leash/1, default are call, exit, redo and fail) the user is prompted for an action. All actions are single character commands which are executed without waiting for a return (Unix ‘cbreak’ mode), unless the command line option -tty is active. Tracer options:

+  Spy  all

Set a spy point (see spy/1) on the current predicate.

−  No spy  all

Remove the spy point (see nospy/1) from the current predicate.

Yes
2 ?- visible(+all), leash(-exit).
Yes
3 ?- trace, min([3, 2], X).
Call:  ( 3) min([3, 2], G235) ? creep
Unify: ( 3) min([3, 2], G235)
Call:  ( 4) min([2], G244) ? creep
Unify: ( 4) min([2], 2)
Exit:  ( 4) min([2], 2)
Call:  ( 4) min(3, 2, G235) ? creep
Unify: ( 4) min(3, 2, G235)
Call:  ( 5) 3 < 2 ? creep
Fail:  ( 5) 3 < 2 ? creep
Redo:  ( 4) min(3, 2, G235) ? creep
Exit:  ( 4) min(3, 2, 2)
Exit:  ( 3) min([3, 2], 2)

Figure 2.3: Example trace

/  Find  all

Search for a port. After the ‘/’, the user can enter a line to specify the port to search for. This line consists of a set of letters indicating the port type, followed by an optional term, that should unify with the goal run by the port. If no term is specified it is taken as a variable, searching for any port of the specified type. If an atom is given, any goal whose functor has a name equal to that atom matches. Examples:

/f  Search for any fail port

/fe solve Search for a fail or exit port of any goal with name

                        solve

/c solve(a, ) Search for a call to solve/2 whose first argument is a variable or the atom a /a member( , ) Search for any port on member/2. This is equiva-

lent to setting a spy point on member/2.

.  Repeat find  all

Repeat the last find command (see ‘/’)

A  Alternatives  all

Show all goals that have alternatives.

C  Context  all

Toggle ‘Show Context’. If on the context module of the goal is displayed between square brackets (see section 4). Default is off.

L  Listing  all

List the current predicate with listing/1.

a  Abort  all

Abort Prolog execution (see abort/0).

b  Break  all

Enter a Prolog break environment (see break/0).

c  Creep  all

Continue execution, stop at next port. (Also return, space).

d  Display  all

Write goals using the Prolog predicate display/1.

e  Exit  all

Terminate Prolog (see halt/0).

f  Fail  call, redo, exit

Force failure of the current goal

g  Goals  all

Show the list of parent goals (the execution stack). Note that due to tail recursion optimization a number of parent goals might not exist any more.

h  Help  all

Show available options (also ‘?’).

i  Ignore  call, redo, fail

Ignore the current goal, pretending it succeeded.

l  Leap  all

Continue execution, stop at next spy point.

n  No debug  all

Continue execution in ‘no debug’ mode.

p  Print  all

Write goals using the Prolog predicate print/1 (default).

r  Retry  redo, exit, fail

Undo all actions (except for database and i/o actions) back to the call port of the current goal and resume execution at the call port.

s  Skip  call, redo

Continue execution, stop at the next port of this goal (thus skipping all calls to children of this goal).

u  Up  all

Continue execution, stop at the next port of the parent goal (thus skipping this goal and all calls to children of this goal). This option is useful to stop tracing a failure driven loop.

w  Write  all

Write goals using the Prolog predicate write/1.

The ideal 4 port model as described in many Prolog books [Clocksin & Mellish, 1981] is not visible in many Prolog implementations because code optimisation removes part of the choice- and exit points. Backtrack points are not shown if either the goal succeeded deterministically or its alternatives were removed using the cut. When running in debug mode (debug/0) choice points are only destroyed when removed by the cut. In debug mode tail recursion optimisation is switched off.^{3}

3This implies the system can run out of local stack in debug mode, while no problems arise when running in non-debug mode.

2.7 Compilation

Collections of SWI-Prolog source files can be compiled into an intermediate code file. An intermediate code file is a data file from which SWI-Prolog can be started. The command to compile a bundle of source files is:

     pl [options] [-o output] -c file ...

The individual source files may include other files using the standard list notation, consult/1,

ensure loaded/1 and use module/[1,2]. When the -o file option is omitted a file named a.out

is created that holds the intermediate code file.

Intermediate code files start with the BSD Unix magic code #! and are executable. This implies they can be started as a command:

     sun% pl -o my_program -c ...
     ...
     sun% my_program [options]

Alternatively, my program can be started with

     sun% pl -x my_program [options]

The following restrictions apply to source files that are to be compiled with ‘-c’:

• term expansion/2 should not use assert/1 and or retract/1 other than for local computational purposes.

• Files can only be included by the standard include directives: [...], consult/1, ensure loaded/1 and use module/[1,2]. User defined loading predicate invocations will not be compiled.

Directives are executed both when compiling the program and when loading the intermediate code file.

2.8 Environment Control

The current system defines 3 different mechanisms to query and/or set properties of the environment: please/3, flag/3 and feature/2 as well as a number of special purpose predicates of which unknown/2, fileerrors/2 are examples. The ISO standard defines prolog flag. It is likely that all these global features will be merged into a single in the future.

please(+Key, -Old, +New)

The predicate please/3^{4} is a solution to avoid large numbers of environment control predicates. Later versions will support other environment control as now provided via the predicates style check/2, leash/1, unknown/2, the tracer predicates, etc. These predicates are then moved into a library for backwards compatibility. The currently available options are: optimise on/off (default: off)

4The idea comes from BIM Prolog. The options supported by this predicate are not compatible with those for BIM Prolog however.

Switch optimise mode for the compiler on or off (see also the command line option -O). Currently optimised compilation only implies compilation of arithmetic, making it fast, but invisible to the tracer. Later versions might imply various other optimisations such as incorporating a number of basic predicates in the virtual machine (var/1, fail/0, =/2, etc.) to gain speed at the cost of crippling the debugger. Also source level optimisations such as integrating small predicates into their callers, eliminating constant expressions and other predictable constructs. Source code optimisation is never applied to predicates that are declared dynamic (see dynamic/1).

autoload on/off (default: on)

If on autoloading of library functions is enabled. If off autoloading is disabled. See section 2.10.

verbose autoload on/off (default: off)

If on the normal consult message will be printed if a library is autoloaded. By default this message is suppressed. Intended to be used for debugging purposes (e.g. where does this predicate come from?).

feature(?Key, -Value)

The predicate feature/2 defines an interface to installation features: options compiled in, version, home, etc. With both arguments unbound, it will generate all defined features. With the ‘Key’ instantiated it unify the value of the feature. Features come in three types: boolean features, features with an atom value and features with an integer value. A boolean feature is true iff the feature is present and the Value is the atom true. Currently defined keys:

arch (atom)

Identifier for the hardware and operating system SWI-Prolog is running on. Used to determine the startup file as well as to select foreign files for the right architecture. See

also load foreign/5.

version (atom)

The version identifier is an atom consisting of 3 numeric values separated by dots (e.g.

1.9.2).

home (atom)

SWI-Prolog’s notion of the home-directory. SWI-Prolog uses it’s home directory to find its startup file as <home>/startup/startup.<arch> and to find its library as <home>/library.

pipe (bool)

If true, tell(pipe(command)), etc. are supported. load foreign (bool)

If true, load foreign/[2,5] are implemented. open shared object (bool)

If true, open shared object/2 and friends are implemented, providing access to shared libraries (.so files). This requires the C-library functions dlopen() and friends as well as the configuration option --with-dlopen.

dynamic stacks (bool)

If true, the system provides virtual memory based stack expansion. This makes stackexpansion safe when called from C and while running C-defined functions without these functions taking any precautions. Pure Prolog programs are not affected by this feature as the system will use stack-shifting to expand the stacks at runtime.

c libs (atom)

Libraries passed to the C-linker when SWI-Prolog was linked. May be used to determine the libraries needed to create statically linked extensions for SWI-Prolog. c staticlibs (atom)

On some machines, the SWI-Prolog executable is dynamically linked, but requires some libraries to be statically linked.

c cc (atom)

Name of the C-compiler used to compile SWI-Prolog. Normally either gcc or cc. c ldflags (atom)

Special linker flags passed to link SWI-Prolog. save (bool)

If true, save/[1,2] is implemented. save program (bool)

If true, save program/[1,2] is implemented. readline (bool)

If true, SWI-Prolog is linked with the readline library. This is done by default if you have this library installed on your system.

saved program (bool)

If true, Prolog is started from a state saved with qsave program/[1,2]. runtime (bool)

If true, SWI-Prolog is compiled with -DO RUNTIME, disabling various useful development features (currently the tracer and profiler).

max integer (integer)

Maximum integer value. Most arithmetic operations will automatically convert to floats if integer values above this are returned.

min integer (integer)

Minimum integer value.

set feature(+Key, +Value)

Define a new feature or change its value. Both arguments must be atoms.

2.9 Saved States

2.9.1 Types of Saved States and Portability

On some architectures, SWI-Prolog allows for the creation of saved states. Currently, the Csources define two alternative implementations for them. The old implementation^{5} creates an entirely self-contained executable. It supports only the save program/[1,2] predicates. The new implementation^{6} creates a file that is read by the ‘base’ program. This file contains the data-area of the SWI-Prolog process and optionally the Prolog- and C stacks. This implementation supports save program/[1,2], save/[1,2] and restore/1. The state-file depends entirely on exactly the Unix program-file used to create it.

2.9.2 Save Predicates

save program(+NewProgram, +ListOfOptions)

Create a new executable wich will be named NewProgram. ListOfOptions is a list of Key = Value pairs that specify the default command line options that will be saved into the new program. If a default is not specified the default compiled into the currently running Prolog executable is used.^{7} The available keys are given in table 2.2

5This implementation is based on GNU’s unexec() function, creating a new executable from the running process.

It is selected using the O STORE PROGRAM option in the machine-description file.

6This implementation is selected by the O SAVE option in the machine-description file.

Key  Option Type Description
local  -L  K-bytes Size (Limit) of local stack
global  -G  K-bytes Size (Limit) of global stack
trail  -T  K-bytes Size (Limit) of trail stack
argument  -A  K-bytes Size (Limit) of argument stack
goal  -g  atom Initialisation goal
toplevel  -t  atom Prolog toplevel goal
init file  -f  atom Personal initialisation file
tty  +/–tty on/off Use ioctl(2) calls

Table 2.2: Key = Value pairs for save program/2

As the entire data image of the current process will be saved on the new executable it is desirable to keep this small. Notably the Prolog machine stacks should be kept small. The best way to do this is first to compile the program using the -c option. If this is not possible try to find the smallest possible stack sizes to compile the program. On machines with dynamic stack allocation the stacks are not written to file and so their size does not matter. Figure 2.4 shows a possible session. Note the use of ‘initialise’, which is supposed to be a predicate of the application doing time consuming initialisation.

The resulting program can be used for incremental compilation using -c or another save program/2.

save program(+NewProgram)

Equivalent to ‘save_program(NewProgram, [])’.

save(+State)

Writes the current status on the program, Prolog- and C-stacks to the file State. When this file is restored, save/1 succeeds in the restored state and execution continues as illustrated by the following example:

     1 ?- save(state), format('Hello World~n').
     Hello World
     Yes
     2 ?- halt.
     machine% ./state
     Hello World
     Yes
     2 ?- h.
         1   save(state), format('Hello World~n').
     2 ?-

The save/1 predicate is normally used for debugging purposes. save program/[1,2] is the preferred way to create a new program.

7These are NOT the defaults compiled into an intermediate code file created with pl -c ...

sun% pl -c load
foreign file dbase loaded 0.066667 seconds, 1578 bytes.
setup consulted, 0.500000 seconds, 5091 bytes.
main consulted, 0.333333 seconds, 3352 bytes.
load consulted, 1.000000 seconds, 9867 bytes.
sun% a.out -f none -L10 -G10 -T5
foreign file dbase loaded 0.066667 seconds, 1578 bytes.
Welcome to SWI-Prolog (version 2.1.3, July 1995)
Copyright (c) 1990-1995, University of Amsterdam. All rights reserved.
1 ?- initialise.
Yes
2 ?- save_program(my_program,
        [ local     = 500
        , goal      = go
        , init_file = none
        ]).
Running executable: /usr/local/bin/pl
Saving to my_program; text: 204800 ... data: 357000 ... symbols ... done.
Yes
2 ?- halt.
sun%

Figure 2.4: Create a stand-alone executable

save(+State, -Rval)

Like save/1, but unifies Rval with 0 when save/2 returns from a real save and with 1 when save/2 returns from a restore.

restore(+State)

Equivalent to restarting State.

2.10 Automatic loading of libraries

If —at runtime— an undefined predicate is trapped the system will first try to import the predicate from the module’s default module. If this fails the auto loader is activated. On first activation an index to all library files in all library directories is loaded in core (see library directory/1). If the undefined predicate can be located in the one of the libraries that library file is automatically loaded and the call to the (previously undefined) predicate is resumed. By default this mechanism loads the file silently. The please/3 option verbose autoload is provided to get verbose loading. The please option autoload can be used to enable/disable the entire auto load system.

Autoloading only handles (library) source files that use the module mechanism described in chapter 4. The files are loaded with use module/2 and only the trapped undefined predicate will be imported to the module where the undefined predicate was called. Each library directory must hold a file INDEX.pl that contains an index to all library files in the directory. This file consists of lines of the following format:

     index(Name, Arity, Module, File).

The predicate make/0 scans the autoload libraries and updates the index if it exists, is writable and out-of-date. It is adviced to create an empty file called INDEX.pl in a library directory meant for auto loading before doing anything else. This index file can then be updated by running the prolog make library index/1 (‘%’ is the Unix prompt):

     % mkdir ~/lib/prolog
     % cd !$
     % pl -g true -t 'make_library_index(.)'

If there are more than one library files containing the desired predicate the following search schema is followed:

1. If a there is a library file that defines the module in which the undefined predicate is trapped, this file is used.

2. Otherwise library files are considered in the order they appear in the library directory/1 predicate and within the directory alphabetically.

make library index(+Directory)

Create an index for this directory. The index is written to the file ’INDEX.pl’ in the specified directory. Fails with a warning if the directory does not exist or is write protected.

2.10.1 Notes on Automatic Loading

The autoloader is a new feature to SWI-Prolog. Its aim is to simplify program development and program management. Common lisp has a similar feature, but here the user has to specify which library is to be loaded if a specific function is called which is not defined. The advantage of the SWI-Prolog schema is that the user does not have to specify this. The disadvantage however is that the user might be wondering “where the hell this predicate comes from”. Only experience can learn whether the functionality of the autoloader is appropriate. Comments are welcome.

The autoloader only works if the unknown flag (see unknown/2) is set to trace (default). A more appropriate interaction with this flag will be considered.

2.11 Garbage Collection

SWI-Prolog version 1.4 was the first release to support garbage collection. Together with tailrecursion optimisation this guaranties forward chaining programs do not waste indefinite amounts of memory. Previous releases of this manual stressed on using failure-driven loops in those cases that no information needed to be passed to the next iteration via arguments. This to avoid large amounts of garbage. This is no longer strictly necessary, but it should be noticed that garbage collection is a time consuming activity. Failure driven loops tend to be faster for this reason.^{8}

8BUG: The garbage collector is deactivated when Prolog is called back from a foreign language predicate. This implies there is no garbage collection within a break environment. More seriously, there is no garbage collection when handling call-backs from —for example— the XPCE package.

2.12 Syntax Notes

SWI-Prolog uses standard ‘Edinburgh’ syntax. A description of this syntax can be found in the Prolog books referenced in the introduction. Below are some non-standard or non-common constructs that are accepted by SWI-Prolog:

   • 0'<char>

This construct is not accepted by all Prolog systems that claim to have Edinburgh compatible syntax. It describes the ASCII value of <char>. To test whether C is a lower case character

     one can use ‘between(0'a, 0'z, C)’.
   • /* ... /* .... */ ... */

The /* ... */ comment statement can be nested. This is useful if some code with /* ... */ comment statements in it should be commented out.

2.13 System Limits

2.13.1 Limits on Memory Areas

SWI-Prolog has a number of memory areas which are not enlarged at run time, unless you have a version with dynamic stack allocation. The default sizes for these areas should suffice for small applications, but most serious application require larger ones. They all can be modified by command line options. The table below shows these areas. The first column gives the option name to modify the size of the area. This option character should be followed immediately by a number and expresses the number of kilo bytes to use for the area. There are no other limits than the available memory of the machine to the sizes of the areas. The areas are described in table 2.3.

The heap is a memory area to store atoms, clauses, records, flags, etc. This area is dynamically enlarged at runtime on all versions of SWI-Prolog.

2.13.2 Other Limits

Clauses Currently the following limitations apply to clauses. The arity may not be more than 128, the number of links to the ‘outside world’ (predicates, atoms, (large) integers, etc) may not exceed 512 and the number of variables should be less than 256.^{9}

Atoms and Strings SWI-Prolog has no limits on the sizes of atoms and strings. read/1 and its derivates however normally limit the number of newlines in an atom or string to 5 to improve error detection and recovery. This can be switched off with style check/1.

Address space SWI-Prolog uses tagged pointers internally. This limits the number of available bits for addressing memory to 29 (512 Mb).

Integers Integers are tagged values. Their value is limited between −2^{26} and 2^{26} − 1.

Floats Floating point numbers are C-doubles with a 12 bit reduction of the mantisse. For machines using IEEE floating point format, this implies the range is about ±10^{308} and the accurracy about 10 digits.

9I plan to raise all these limits to 65536, the maximum addressable range by the 16 bits virtual machine codes.

Option Default^{a} Area name  Description
-L  200K (2M) local stack  The local stack is used to store

the execution environments of procedure invocations. The space for an environment is reclaimed when it fails, exits without leaving choice points, the alternatives are cut of with the ! predicate or no choice points have been created since the invocation and the last subclause is started (tail recursion optimisation).

-G 100K (4M) global stack The global stack is used to store terms created during Prolog’s execution. Terms on this stack will be reclaimed by backtracking to a point before the term was created or by garbage collection (provided the term is no longer referenced).

-T 50K (4M) trail stack The trail stack is used to store assignments during execution. Entries on this stack remain alive until backtracking before the point of creation or the garbage collector determines they are nor needed any longer.

-A 5K (1M) argument stack The argument stack is used to store one of the intermediate code interpreter’s registers. The amount of space needed on this stack is determined entirely by the depth in which terms are nested in the clauses that constitute the program. Overflow is most likely when using long strings in a clause.

Table 2.3: Memory areas

aDefaults may depend on local installation. The value between brackets is the default limit for machines that allow for dynamic stack allocation.

2.13.3 Reserved Names

The boot compiler (see -b option) does not support the module system (yet). As large parts of the system are written in Prolog itself we need some way to avoid name clashes with the user’s predicates, database keys, etc. Like Edinburgh C-Prolog [Pereira, 1986] all predicates, database keys, etc. that should be hidden from the user start with a dollar ($) sign (see style check/2).

The compiler uses the special functor $VAR$/1 while analysing the clause to compile. Using this functor in a program causes unpredictable behaviour of the compiler and resulting program.

CHAPTER 2. OVERVIEW 2.1 – 24 –

Built-In Predicates

3.1 Notation of Predicate Descriptions

We have tried to keep the predicate descriptions clear and concise. First the predicate name is printed in bold face, followed by the arguments in italics. Arguments are preceded by a ‘+’, ‘–’ or ‘?’ sign. ‘+’ indicates the argument is input to the predicate, ‘–’ denotes output and ‘?’ denotes ‘either input or output’.^{1} Constructs like ‘op/3’ refer to the predicate ‘op’ with arity ‘3’.

3.2 Consulting Prolog Source files

SWI-Prolog source files normally have a suffix ‘.pl’. Specifying the suffix is optional. All predicates that handle source files first check whether a file with suffix ‘.pl’ exists. If not the plain file name is checked for existence. Library files are specified by embedding the file name using the functor library/1. Thus ‘foo’ refers to ‘foo.pl’ or ‘foo’ in the current directory, ‘library(foo)’ refers to ‘foo.pl’ or ‘foo’ in one of the library directories specified by the dynamic predicate

library directory/1.

SWI-Prolog recognises grammar rules as defined in [Clocksin & Mellish, 1981]. The user may define additional compilation of the source file by defining the dynamic predicate term expansion/2. Transformations by this predicate overrule the systems grammar rule transformations. It is not allowed to use assert/1, retract/1 or any other database predicate in term expansion/2 other than for local computational purposes.^{2}

Directives may be placed anywhere in a source file, invoking any predicate. They are executed when encountered. If the directive fails, a warning is printed. Directives are specified by :-/1 or ?-/1. There is no difference between the two.

SWI-Prolog does not have a separate reconsult/1 predicate. Reconsulting is implied automatically by the fact that a file is consulted which is already loaded.

consult(+File)

Read File as a Prolog source file. File may be a list of files, in which case all members are consulted in turn. File may start with the csh(1) special sequences ~, ~<user> and $<var>.

1These marks do NOT suggest instanstiation (e.g. var(+Var)).

2It does work for consult, but makes it impossible to compile programs into a stand alone executable (see section 2.7)

CHAPTER 3. BUILT-IN PREDICATES 2.1

File may also be library(Name), in which case the libraries are searched for a file with the

specified name. See also library directory/1 and file search path/2. consult/1 may be

abbreviated by just typing a number of file names in a list. Examples:

?- consult(load).  % consult ‘load’ or ‘load.pl’
?- [library(quintus)]. % load Quintus compatibility library

ensure loaded(+File)

If the file is not already loaded, this is equivalent to consult/1. Otherwise, if the file defines a module, import all public predicates. Finally, if the file is already loaded, is not a module file and the context module is not the global user module, ensure loaded/1 will call consult/1. With the semantics, we hope to get as closely possible to the clear semantics without the presence of a module system. Applications using modules should consider using use module/[1,2].

require(+ListOfNameAndArity)

Declare that this file/module requires the specified predicates to be defined “with their commonly accepted definition”. This predicate originates from the Prolog portability layer for XPCE. It is intended to provide a portable mechanism for specifying that this module requires the specified predicates. The implementation normally first verifies whether the predicate is already defined. If not, it will search the libraries and load the required library. SWI-Prolog, having autoloading, does not load the library. Instead it creates a procedure header for the predicate if this does not exist. This will flag the predicate as ‘undefined’. See

also check/0 and autoload/0.

make Consult all source files that have been changed since they were consulted. It checks all loaded source files: files loaded into a compiled state using pl -c ... and files loaded using consult or one of its derivates. make/0 is normally invoked by the edit/[0,1] and ed/[0,1] predicates. make/0 can be combined with the compiler to speed up the development of large packages. In this case compile the package using

    sun% pl -g make -o my_program -c file ...

If ‘my program’ is started it will first reconsult all source files that have changed since the compilation.

library directory(-Atom)

Dynamic predicate used to specify library directories. Default ., ./lib, ~/lib/prolog and the system’s library (in this order) are defined. The user may add library directories using assert/1, asserta/1 or remove system defaults using retract/1.

file search path(+Alias, -Path)

Dynamic predicate used to specify ‘path-aliases’. This feature is best described using an example. Given the definition

    file_search_path(demo, '~/demo').

the file specification demo(myfile) will be expanded to ' /demo/myfile'. The second argument of file search path/2 may be another alias. Below is the initial definition of the file search path. This path implies swi(Path) refers to a file in the SWI-Prolog home directory. The alias foreign(Path) is intended for storing shared

libraries (.so or .dll files). See also load foreign library/[1,2].

    file_search_path(library, X) :-
            library_directory(X).
    user:file_search_path(swi, Home) :-
            feature(home, Home).
    user:file_search_path(foreign, swi(ArchLib)) :-
            feature(arch, Arch),
            concat('lib/', Arch, ArchLib).
    user:file_search_path(foreign, swi(lib)).

The file search path/2 expansion is used by all loading predicates as well as by absolute file name/2.

source file(-File)

Succeeds if File was loaded using consult/1 or ensure loaded/1. File refers to the full path name of the file (see expand file name/2). Source file/1 backtracks over all loaded source files.

source file(?Pred, ?File)

Is true if the predicate specified by Pred was loaded from file File, where File is an absolute path name (see expand file name/2). Can be used with any instantiation pattern, but the database only maintains the source file for each predicate. Predicates declared multifile (see multifile/1) cannot be found this way.

prolog load context(?Key, ?Value)

Determine loading context. The following keys are defined:

Key  Description

module Module into which file is loaded

file           File loaded

    stream  Stream identifier (see current stream/1)

directory Directory in which File lives.

term position Postion of last term read. Term of the form ’$stream position’(0,Line,0,0,0)

Quintus compatibility predicate. See also source location/2.

source location(-File, -Line)

If the last term has been read from a physical file (i.e. not from the file user or a string), unify File with an absolute path to the file and Line with the line-number in the file. New code

should use prolog load context/2.

term expansion(+Term1, -Term2)

Dynamic predicate, normally not defined. When defined by the user all terms read during consulting that are given to this predicate. If the predicate succeeds Prolog will assert Term2 in the database rather then the read term (Term1). Term2 may be a term of a the form ‘?- Goal’ or ‘:- Goal’. Goal is then treated as a directive. Term2 may also be a list, in which case all terms of the list are stored in the database or called (for directives). See also expand term/2.

expand term(+Term1, -Term2)

This predicate is normally called by the compiler to perform preprocessing. First it calls term expansion/2. If this predicate fails it performs a grammar-rule translation. If this fails it returns the first argument. at initialization(+Goal)

Register Goal to be ran when the system initialises. Initialisation takes place after reloading a .qlf (formerly .wic) file as well as after reloading a saved-state. The hooks are ran in the order they were registered. A warning message is issued if Goal fails, but execution continues. See

     also at halt/1

at halt(+Goal)

Register Goal to be ran when the system halts. The hooks are ran in the order they were registered. Success or failure executing a hook is ignored. These hooks may not call halt/[0,1].

initialization(+Goal)

Call Goal and register it using at initialization/1. Directives that do other things that creating clauses, records, flags or setting predicate attributes should normally be written using this tag to ensure the initialisation is executed when a saved system starts. See also

     qsave program/[1,2].

compiling Succeeds if the system is compiling source files with the -c option into an intermediate code file. Can be used to perform code optimisations in expand term/2 under this condition.

preprocessor(-Old, +New)

Read the input file via a Unix process that acts as preprocessor. A preprocessor is specified as an atom. The first occurrence of the string ‘%f’ is replaced by the name of the file to be loaded. The resulting atom is called as a Unix command and the standard output of this command is loaded. To use the Unix C preprocessor one should define:

         ?- preprocessor(Old, '/lib/cpp -C -P %f'), consult(...).
         Old = none

3.2.1 Quick Load Files

The features described in this section should be regarded alpha.

As of version 2.0.0, SWI-Prolog supports compilation of individual or multiple Prolog sourcefiles into ‘Quick Load Files’. A ‘Quick Load Files’ (.qlf file) stores the contents of the file in a precompiled format very similar to compiled files created using the -b and -c flags (see section 2.7).

These files load considerably faster than sourcefiles and are normally more compact. They are machine independent and may thus be loaded on any implementation of SWI-Prolog. Note however that clauses are stored as virtual machine instructions. Changes to the compiler will generally make old compiled files unusable.

Quick Load Files are created using qcompile/1. They may be loaded explicitely using qload/1 or implicitely using consult/1 or one of the other file-loading predicates described in section 3.2. If consult is given the explicit .pl file, it will load the Prolog source. When given the .qlf file, it will call qload/1 to load the file. When no extension is specified, it will load the .qlf file when present and the .pl file otherwise.

qcompile(+File)

Takes a single file specification like consult/1 (i.e. accepts constructs like library(LibFile) and creates a Quick Load File from File. The file-extension of this file is .qlf. The base name of the Quick Load File is the same as the input file.

If the file contains ‘:- consult(+File)’ or ‘:- [+File]’ statements, the referred files are compiled into the same .qlf file. Other directives will be stored in the .qlf file and executed in the same fashion as when loading the .pl file.

For term expansion/2, the same rules as described in section 2.7 apply.

Source references (source file/2) in the Quick Load File refer to the Prolog source file from which the compiled code originates.

qload(+File)

Loads the ‘Quick Load File’. It has the same semantics as consult/1 for a normal sourcefile. Equivalent to consult(File) iff File refers to a ‘Quick Load File’.

3.3 Listing Predicates and Editor Interface

SWI-Prolog offers an interface to the Unix vi editor (vi(1)), Richard O’Keefe’s top editor [O’Keefe, 1985] and the GNU-EMACS invocations emacs and emacsclient. Which editor is used is determined by the Unix environment variable EDITOR, which should hold the full pathname of the editor. If this variable is not defined, vi(1) is used.

After the user quits the editor make/0 is invoked to reload all modified source files using consult/1. If the editor can be quit such that an exit status non-equal to 0 is returned make/0 will not be invoked. top can do this by typing control-C, vi cannot do this.

A predicate specification is either a term with the same functor and arity as the predicate wanted, a term of the form Functor/Arity or a single atom. In the latter case the database is searched for a predicate of this name and arbitrary arity (see current predicate/2). When more than one such predicate exists the system will prompt for confirmation on each of the matched predicates. Predicates specifications are given to the ‘Do What I Mean’ system (see dwim predicate/2) if the requested predicate does not exist.

ed(+Pred)

Invoke the user’s preferred editor on the source file of Pred, providing a search specification which searches for the predicate at the start of a line.

ed Invoke ed/1 on the predicate last edited using ed/1. Asks the user to confirm before starting the editor.

edit(+File)

Invoke the user’s preferred editor on File. File is a file specification as for consult/1 (but not a list). Note that the file should exist.

edit Invoke edit/1 on the file last edited using edit/1. Asks the user to confirm before starting the editor.

listing(+Pred)

List specified predicates (when an atom is given all predicates with this name will be listed). The listing is produced on the basis of the internal representation, thus loosing user’s layout and variable name information. See also portray clause/1.

listing List all predicates of the database using listing/1. portray clause(+Clause)

Pretty print a clause as good as we can. A clause should be specified as a term ‘Head :- Body’ (put brackets around it to avoid operator precedence problems). Facts are represented as

     ‘Head :- true’.

3.4 Verify Type of a Term

var(+Term)

Succeeds if Term currently is a free variable.

nonvar(+Term)

Succeeds if Term currently is not a free variable.

integer(+Term)

Succeeds if Term is bound to an integer.

float(+Term)

Succeeds if Term is bound to a floating point number.

number(+Term)

Succeeds if Term is bound to an integer or a floating point number.

atom(+Term)

Succeeds if Term is bound to an atom.

string(+Term)

Succeeds if Term is bound to a string.

atomic(+Term)

Succeeds if Term is bound to an atom, string, integer or floating point number.

compound(+Term)

Succeeds if Term is bound to a compound term. See also functor/3 and =../2.

ground(+Term)

Succeeds if Term holds no free variables.

3.5 Comparison and Unification or Terms

3.5.1 Standard Order of Terms

Comparison and unification of arbitrary terms. Terms are ordered in the so called “standard order”. This order is defined as follows:

1. Variables < Atoms < Strings^{3} < Numbers < Terms

2. Old Variable < New Variable^{4}

3. Atoms are compared alphabetically.

4. Strings are compared alphabetically.

3Strings might be considered atoms in future versions. See also section 3.19

4In fact the variables are compared on their (dereferenced) addresses. Variables living on the global stack are always < than variables on the local stack. Programs should not rely on the order in which variables are sorted.

5. Numbers are compared by value. Integers and floats are treated identically.

6. Terms are first checked on their functor (alphabetically), then on their arity and finally recursively on their arguments, leftmost argument first.

+Term1 == +Term2 Succeeds if Term1 is equivalent to Term2. A variable is only identical to a sharing variable.

+Term1 \== +Term2 Equivalent to ‘\+ Term1 == Term2’.

+Term1 = +Term2 Unify Term1 with Term2. Succeeds if the unification succeeds.

+Term1 \= +Term2 Equivalent to ‘\+ Term1 = Term2’.

+Term1 =@= +Term2 Succeeds if Term1 is ‘structurally equal’ to Term2. Structural equivalence is weaker than equivalence (==/2), but stronger than unification (=/2). Two terms are structurally equal if their tree representation is identical and they have the same ‘pattern’ of variables. Examples:

               a =@= A  false
               A =@= B  true
          x(A,A) =@= x(B,C) false
          x(A,A) =@= x(B,B) true
          x(A,B) =@= x(C,D) true

+Term1 \=@= +Term2

     Equivalent to `\+ Term1 =@= Term2'.

+Term1 @< +Term2 Succeeds if Term1 is before Term2 in the standard order of terms.

+Term1 @=< +Term2 Succeeds if both terms are equal (==) or Term1 is before Term2 in the standard order of terms.

+Term1 @> +Term2 Succeeds if Term1 is after Term2 in the standard order of terms.

+Term1 @>= +Term2 Succeeds if both terms are equal (==) or Term1 is after Term2 in the standard order of terms.

3.6 Control Predicates

The predicates of this section implement control structures. Normally these constructs are translated into virtual machine instructions by the compiler. It is still necessary to implement these constructs as true predicates to support meta-calls, as demonstrated in the example below. The predicate finds all currently defined atoms of 1 character long. Note that the cut has no effect when called via one of these predicates (see !/0).

     one_character_atoms(As) :-
             findall(A, (current_atom(A), atom_length(A, 1)), As).

fail Always fail. The predicate fail/0 is translated into a single virtual machine instruction.

true Always succeed. The predicate true/0 is translated into a single virtual machine instruction.

repeat Always succeed, provide an infinite number of choice points.

!

Cut. Discard choice points of parent frame and frames created after the parent frame. Note that the control structures ;/2, |/2 ->/2 and \+/1 are normally handled by the compiler and do not create a frame, which implies the cut operates through these predicates. Some examples are given below. Note the difference between t3/1 and t4/1. Also note the effect of call/1 in t5/0. As the argument of call/1 is evaluated by predicates rather than the compiler the cut has no effect.

          t1 :- (a, !, fail ; b).  % cuts a/0 and t1/0
          t2 :- (a -> b, !  ; c).  % cuts b/0 and t2/0
          t3(G) :- a, G, fail.  % if ‘G = !’ cuts a/0 and t1/1
          t4(G) :- a, call(G), fail.  % if ‘G = !’ cut has no effect
          t5 :- call((a, !, fail ; b)). % Cut has no effect
          t6 :- \+ (a, !, fail ; b).  % cuts a/0 and t6/0

+Goal1 , +Goal2 Conjunction. Succeeds if both ‘Goal1’ and ‘Goal2’ can be proved. It is defined as (this definition does not lead to a loop as the second comma is handled by the compiler):

    Goal1, Goal2 :- Goal1, Goal2.

+Goal1 ; +Goal2 The ‘or’ predicate is defined as:

    Goal1 ; _Goal2 :- Goal1.
    _Goal1 ; Goal2 :- Goal2.

+Goal1 | +Goal2 Equivalent to ;/2. Retained for compatibility only. New code should use ;/2. Still nice though for grammar rules.

+Condition -> +Action If-then and If-Then-Else. Implemented as:

    If -> Then; _Else :- If, !, Then.
    If -> _Then; Else :- !, Else.
    If -> Then :- If, !, Then.

\+ +Goal Succeeds if ‘Goal’ cannot be proven (mnemnonic: + refers to provable and the backslash is normally used to indicate negation).

3.7 Meta-Call Predicates

Meta call predicates are used to call terms constructed at run time. The basic meta-call mechanism offered by SWI-Prolog is to use variables as a subclause (which should of course be bound to a valid goal at runtime). A meta-call is slower than a normal call as it involves actually searching the database at runtime for the predicate, while for normal calls this search is done at compile time.

call(+Goal)

Invoke Goal as a goal. Note that clauses may have variables as subclauses, which is identical to call/1, except when the argument is bound to the cut. See !/0. .C call [2..] +Goal, +ExtraArg1, ... Append ExtraArg1, ExtraArg2, ... to the argument list of Goal and call the result. For example, call(plus(1), 2, X) will call plus/3, binding X to 3. The call/[2..] construct is handled by the compiler, which implies that redefinition as a predicate has no effect. The predicates call/[2-6] are defined as true predicates, so they can be handled by interpreted code.

apply(+Term, +List)

Append the members of List to the arguments of Term and call the resulting term. For example: ‘apply(plus(1), [2, X])’ will call ‘plus(1, 2, X)’. Apply/2 is incorporated in the virtual machine of SWI-Prolog. This implies that the overhead can be compared to the overhead of call/1.

not +Goal Succeeds when Goal cannot be proven. Retained for compatibility only. New code should use

\+/1.

once(+Goal)

Defined as:

    once(Goal) :-
            Goal, !.

Once/1 can in many cases be replaced with ->/2. The only difference is how the cut behaves (see !/0). The following two clauses are identical:

    1) a :- once((b, c)), d.
    2) a :- b, c -> d.

ignore(+Goal)

Calls Goal as once/1, but succeeds, regardless of whether Goal succeeded or not. Defined as:

    ignore(Goal) :-
            Goal, !.
    ignore(_).

3.8 Advanced control-structures: blocks

The predicates of this section form a tightly related set for realising premature successfull or failing exits from a block. These predicates are first of all useful for error-recovery. They were primarily implemented for compatibily reasons. block(+Label, +Goal, -ExitValue)

Execute Goal in a block. Label is the name of the block. Label is normally an atom, but the system imposes no type constraints and may even be a variable. ExitValue is normally unified to the second argument of an exit/2 call invoked by Goal.

exit(+Label, +Value)

Calling exit/2 makes the innermost block which Label unifies exit. The block’s ExitValue is unified with Value. If this unification fails the block fails.

fail(+Label)

Calling fail/1 makes the innermost block which Label unifies fail immediately. Implemented as

    fail(Label) :- !(Label), fail.

!(+Label)

Cut all choice-points created since the entry of the innermost block which Label unifies.

The example below illustrate these constructs to immediately report a syntax-error from a ‘deepdown’ procedure to the outside world without passing it as an argument ‘all-over-the-place’.

 parse(RuleSet, InputList, Rest) :-
         block(syntaxerror, phrase(RuleSet, InputList, Rest), Error),
         (   var(Error)
         ->  true
         ;   format('Syntax-error: ~w~n', Error),
             fail
         ).
 integer(N) -->
         digit(D1), !, digits(Ds),
         { name(N, [D1|Ds]) }.
 digits([D|R]) --> digit(D), digits(R).
 digits(_) --> letter(_), !, { exit(syntaxerror, 'Illegal number') }.
 digits([]) --> [].
 digit(D, [D|R], R)  :- between(0'0, 0'9, D).
 letter(D, [D|R], R) :- between(0'a, 0'z, D).

3.9 Grammar rule interface (phrase)

The predicates below may be called to activate a grammar-rule set:

phrase(+RuleSet, +InputList)

Equivalent to phrase(RuleSet, InputList, []).

phrase(+RuleSet, +InputList, -Rest)

Activate the rule-set with given name. ‘InputList’ is the list of tokens to parse, ‘Rest’ is unified with the remaining tokens if the sentence is parsed correctly.

3.10 Database

SWI-Prolog offers three different database mechanisms. The first one is the common assert/retract mechanism for manipulating the clause database. As facts and clauses asserted using assert/1 or one of it’s derivates become part of the program these predicates compile the term given to them. Retract/1 and retractall/1 have to unify a term and therefore have to decompile the program. For these reasons the assert/retract mechanism is expensive. On the other hand, once compiled, queries to the database are faster than querying the recorded database discussed below. See also

dynamic/1.

The second way of storing arbitrary terms in the database is using the “recorded database”. In this database terms are associated with a key. A key can be an atom, integer or term. In the last case only the functor and arity determine the key. Each key has a chain of terms associated with it. New terms can be added either at the head or at the tail of this chain. This mechanism is considerably faster than the assert/retract mechanism as terms are not compiled, but just copied into the heap.

The third mechanism is a special purpose one. It associates an integer or atom with a key, which is an atom, integer or term. Each key can only have one atom or integer associated with it. It again is considerably faster than the mechanisms described above, but can only be used to store simple status information like counters, etc.

abolish(+Functor, +Arity)

Removes all clauses of a predicate with functor Functor and arity Arity from the database. Unlike version 1.2, all predicate attributes (dynamic, multifile, index, etc.) are reset to their defaults. Abolishing an imported predicate only removes the import link; the predicate will keep its old definition in its definition module. For ‘cleanup’ of the dynamic database, one

     should use retractall/1 rather than abolish/2.

redefine system predicate(+Head)

This directive may be used both in module user and in normal modules to redefine any system predicate. If the system definition is redefined in module user, the new definition is the default definition for all sub-modules. Otherwise the redefinition is local to the module. The system definition remains in the module system.

Redefining system predicate facilates the definition of compatibility packages. Use in other context is discouraged.

retract(+Term)

When Term is an atom or a term it is unified with the first unifying fact or clause in the database. The fact or clause is removed from the database.

retractall(+Head)

Allfacts or clauses in the database for which the head unifies with Head are removed.^{5}

assert(+Term)

Assert a fact or clause in the database. Term is asserted as the last fact or clause of the corresponding predicate.

asserta(+Term)

Equivalent to assert/1, but Term is asserted as first clause or fact of the predicate.

assertz(+Term)

Equivalent to assert/1. assert(+Term, -Reference)

5Note that the definition has changed since version 2.0.6. See release notes.

Equivalent to assert/1, but Reference is unified with a unique reference to the asserted clause. This key can later be used with clause/3 or erase/1.

asserta(+Term, -Reference)

Equivalent to assert/2, but Term is asserted as first clause or fact of the predicate.

assertz(+Term, -Reference)

Equivalent to assert/2.

recorda(+Key, +Term, -Reference)

Assert Term in the recorded database under key Key. Key is an integer, atom or term. Reference is unified with a unique reference to the record (see erase/1).

recorda(+Key, +Term)

Equivalent to recorda(Key, Value,  ).

recordz(+Key, +Term, -Reference)

Equivalent to recorda/3, but puts the Term at the tail of the terms recorded under Key.

recordz(+Key, +Term)

Equivalent to recordz(Key, Value,  ).

recorded(+Key, -Value, -Reference)

Unify Value with the first term recorded under Key which does unify. Reference is unified with the memory location of the record.

recorded(+Key, -Value)

Equivalent to recorded(Key, Value,  ).

erase(+Reference)

Erase a record or clause from the database. Reference is an integer returned by recorda/3

or recorded/3, clause/3, assert/2, asserta/2 or assertz/2. Other integers might conflict

with the internal consistency of the system. Erase can only be called once on a record or clause. A second call also might conflict with the internal consistency of the system.^{6}

flag(+Key, -Old, +New)

Key is an atom, integer or term. Unify Old with the old value associated with Key. If the key is used for the first time Old is unified with the integer 0. Then store the value of New, which should be an integer, atom or arithmetic integer expression, under Key. flag/3 is a very fast mechanism for storing simple facts in the database. Example:

    :- module_transparent succeeds_n_times/2.
    succeeds_n_times(Goal, Times) :-
            flag(succeeds_n_times, _, 0),
            Goal,
            flag(succeeds_n_times, N, N+1),
            fail ; flag(succeeds_n_times, Times, Times).

6BUG: The system should have a special type for pointers, thus avoiding the Prolog user having to worry about consistency matters. Currently some simple heuristics are used to determine whether a reference is valid.

3.10.1 Indexing databases

By default, SWI-Prolog, as most other implementations, indexes predicates on their first argument. SWI-Prolog allows indexing on other and multiple arguments using the declaration index/1.

For advanced database indexing, it defines hash term/2:

hash term(+Term, -HashKey)

If Term is a ground term (see ground/1), HashKey is unified with a positive integer value that may be used as a hash-key to the value. If Term is not ground, the predicate succeeds immediately, leaving HashKey an unbound variable.

This predicate may be used to build hash-tables as well as to exploit argument-indexing to find complex terms more quickly.

The hash-key does not rely on temporary information like addresses of atoms and may be assumed constant over different invokations of SWI-Prolog.

3.11 Declaring Properties of Predicates

This section describes directives which manipulate attributes of predicate definitions. The functors dynamic/1, multifile/1 and discontiguous/1 are operators of priority 1150 (see op/3), which implies the list of predicates they involve can just be a comma separated list:

:- dynamic
        foo/0,
        baz/2.

On SWI-Prolog all these directives are just predicates. This implies they can also be called by a program. Do not rely on this feature if you want to maintain portability to other Prolog implementations.

dynamic +Functor/+Arity, ...

Informs the interpreter that the definition of the predicate(s) may change during execution (using assert/1 and/or retract/1). Currently dynamic/1 only stops the interpreter from complaining about undefined predicates (see unknown/2). Future releases might prohibit assert/1 and retract/1 for not-dynamic declared procedures.

multifile +Functor/+Arity, ...

Informs the system that the specified predicate(s) may be defined over more than one file. This stops consult/1 from redefining a predicate when a new definition is found.

discontiguous +Functor/+Arity, ...

Informs the system that the clauses of the specified predicate(s) might not be together in the source file. See also style check/1.

index(+Head)

Index the clauses of the predicate with the same name and arity as Head on the specified arguments. Head is a term of which all arguments are either ‘1’ (denoting ‘index this argument’) or ‘0’ (denoting ‘do not index this argument’). Indexing has no implications for the semantics of a predicate, only on its performance. If indexing is enabled on a predicate a special purpose algorithm is used to select candidate clauses based on the actual arguments of the goal. This algorithm checks whether indexed arguments might unify in the clause head. Only atoms, integers and functors (e.g. name and arity of a term) are considered. Indexing is very useful for predicates with many clauses representing facts.

Due to the representation technique used at most 4 arguments can be indexed. All indexed arguments should be in the first 32 arguments of the predicate. If more than 4 arguments are specified for indexing only the first 4 will be accepted. Arguments above 32 are ignored for indexing.

By default all predicates with arity ≥ 1 are indexed on their first argument. It is possible to redefine indexing on predicates that already have clauses attached to them. This will initiate a scan through the predicate’s clause list to update the index summary information stored with each clause.

If –for example– one wants to represents sub-types using a fact list ‘sub type(Sub, Super)’ that should be used both to determine sub- and super types one should declare sub type/2 as follows:

     :- index(sub_type(1, 1)).
     sub_type(horse, animal).
     ...
     ...

3.12 Examining the Program

current atom(-Atom)

Successively unifies Atom with all atoms known to the system. Note that current atom/1 always succeeds if Atom is intantiated to an atom.

current functor(?Name, ?Arity)

Successively unifies Name with the name and Arity with the arity of functors known to the system.

current flag(-FlagKey)

Successively unifies FlagKey with all keys used for flags (see flag/3).

current key(-Key)

Successively unifies Key with all keys used for records (see recorda/3, etc.).

current predicate(?Name, ?Head)

Successively unifies Name with the name of predicates currently defined and Head with the most general term built from Name and the arity of the predicate. This predicate succeeds for all predicates defined in the specified module, imported to it, or in one of the modules from which the predicate will be imported if it is called.

predicate property(?Head, ?Property)

Succeeds if Head refers to a predicate that has property Property. Can be used to test whether a predicate has a certain property, obtain all properties known for Head, find all predicates having property or even obtaining all information available about the current program. Property is one of: interpreted

Is true if the predicate is defined in Prolog. We return true on this because, although the code is actually compiled, it is completely transparent, just like interpreted code.

built in Is true if the predicate is locked as a built-in predicate. This implies it cannot be redefined in it’s definition module and it can normally not be seen in the tracer.

foreign

Is true if the predicate is defined in the C language. dynamic

Is true if the predicate is declared dynamic using the dynamic/1 declaration. multifile

Is true if the predicate is declared multifile using the multifile/1 declaration. undefined

Is true if a procedure definition block for the predicate exists, but there are no clauses in it and it is not declared dynamic. This is true if the predicate occurs in the body of a loaded predicate, an attempt to call it has been made via one of the meta-call predicates or the predicate had a definition in the past. See the library package check for example usage.

transparent Is true if the predicate is declared transparent using the module transparent/1 declaration.

exported

Is true if the predicate is in the public list of the context module. imported from(Module)

Is true if the predicate is imported into the context module from module Module. indexed(Head)

Predicate is indexed (see index/1) according to Head. Head is a term whose name and arity are identical to the predicate. The arguments are unified with ‘1’ for indexed arguments, ‘0’ otherwise.

file(FileName)

Unify FileName with the name of the sourcefile in which the predicate is defined. See

also source file/2.

line count(LineNumber)

Unify LineNumber with the line number of the first clause of the predicate. Fails if the predicate is not associated with a file. See also source file/2.

dwim predicate(+Term, -Dwim)

‘Do What I Mean’ (‘dwim’) support predicate. Term is a term, which name and arity are used as a predicate specification. Dwim is instantiated with the most general term built from Name and the arity of a defined predicate that matches the predicate specified by Term in the ‘Do What I Mean’ sence. See dwim match/2 for ‘Do What I Mean’ string matching. Internal system predicates are not generated, unless style check(+dollar) is active. Backtracking provides all alternative matches.

clause(?Head, ?Body)

Succeeds when Head can be unified with a clause head and Body with the corresponding clause body. Gives alternative clauses on backtracking. For facts Body is unified with the atom true. Normally clause/2 is used to find clause definitions for a predicate, but it can also be used to find clause heads for some body template. clause(?Head, ?Body, ?Reference)

Equivalent to clause/2, but unifies Reference with a unique reference to the clause (see also assert/2, erase/1). If Reference is instantiated to a reference the clause’s head and body will be unified with Head and Body.

nth clause(?Pred, ?Index, ?Reference)

Provides access to the clauses of a predicate using their index number. Counting starts at 1. If Reference is specified it unifies Pred with the most general term with the same name/arity as the predicate and Index with the index-number of the clause. Otherwise the name and arity of Pred are used to determine the predicate. If Index is provided Reference will be unified with the clause reference. If Index is unbound, backtracking will yield both the indices and the references of all clauses of the predicate. The following example finds the 2nd clause of

     member/2:
         ?- nth_clause(member(_,_), 2, Ref), clause(Head, Body, Ref).
         Ref = 160088
         Head = system : member(G575, [G578|G579])
         Body = member(G575, G579)

clause property(+ClauseRef, -Property)

Queries properties of a clause. ClauseRef is a reference to a clause as produced by clause/3,

     nth clause/3 or prolog frame attribute/3. Property is one of the following:

file(FileName)

Unify FileName with the name of the sourcefile in which the clause is defined. Fails if the clause is not associated to a file.

line count(LineNumber)

Unify LineNumber with the line number of the clause. Fails if the clause is not associated to a file.

3.13 Input and Output

SWI-Prolog provides two different packages for input and output. One confirms to the Edinburgh standard. This package has a notion of ‘current-input’ and ‘current-output’. The reading and writing predicates implicitely refer to these streams. In the second package, streams are opened explicitely and the resulting handle is used as an argument to the reading and writing predicate to specify the source or destination. Both packages are fully integrated; the user may switch freely between them.

3.13.1 Input and Output Using Implicit Source and Destination

The package for implicit input and output destination is upwards compatible to DEC-10 and C-Prolog. The reading and writing predicates refer to resp. the current input- and output stream. Initially these streams are connected to the terminal. The current output stream is changed using tell/1 or append/1. The current input stream is changed using see/1. The stream’s current value can be obtained using telling/1 for output- and seeing/1 for input streams. The table below shows the valid stream specifications. The reserved names user input, user output and user error are for neat integration with the explicit streams. user This reserved name refers to the terminal user input Input from the terminal user output Output to the terminal stderr or user error Unix error stream (output only) Atom Name of a Unix file pipe(Atom) Name of a Unix command

Source and destination are either a file, one of the reserved words above, or a term ‘pipe(Command)’. In the predicate descriptions below we will call the source/destination argument ‘SrcDest’. Below are some examples of source/destination specifications.

?- see(data).  % Start reading from file ‘data’.
?- tell(stderr).  % Start writing on the error stream.
?- tell(pipe(lpr)). % Start writing to the printer.

Another example of using the pipe/1 construct is shown on in figure 3.1. Note that the pipe/1 construct is not part of Prolog’s standard I/O reportoire.

     getwd(Wd) :-
             seeing(Old), see(pipe(pwd)),
             collect_wd(String),
             seen, see(Old),
             name(Wd, String).
     collect_wd([C|R]) :-
             get0(C), C \== -1, !,
             collect_wd(R).
     collect_wd([]).

Figure 3.1: Get the working directory

see(+SrcDest)

Make SrcDest the current input stream. If SrcDest was already opened for reading with see/1 and has not been closed since, reading will be resumed. Otherwise SrcDest will be opened and the file pointer is positioned at the start of the file.

tell(+SrcDest)

Make SrcDest the current output stream. If SrcDest was already opened for writing with tell/1 or append/1 and has not been closed since, writing will be resumed. Otherwise the file is created or –when existing– truncated. See also append/1.

append(+File)

Similar to tell/1, but positions the file pointer at the end of File rather than truncating an existing file. The pipe construct is not accepted by this predicate.

seeing(?SrcDest)

Unify the name of the current input stream with SrcDest.

telling(?SrcDest)

Unify the name of the current output stream with SrcDest. seen

Close the current input stream. The new input stream becomes user.

told Close the current output stream. The new output stream becomes user.

3.13.2 Explicit Input and Output Streams

The predicates below are part of the Quintus compatible stream-based I/O package. In this package streams are explicitely created using the predicate open/3. The resulting stream identifier is then passed as a parameter to the reading and writing predicates to specify the source or destination of the data.

open(+SrcDest, +Mode, ?Stream)

SrcDest is either an atom, specifying a Unix file, or a term ‘pipe(Command)’, just like see/1 and tell/1. Mode is one of read, write or append. Stream is either a variable, in which case it is bound to a small integer identifying the stream, or an atom, in which case this atom will be the stream indentifier. In the latter case the atom cannot be an already existing stream identifier. Examples:

       ?- open(data, read, Stream).  % Open ‘data’ for reading.
       ?- open(pipe(lpr), write, printer). % ‘printer’ is a stream to ‘lpr’.

open null stream(?Stream)

On Unix systems, this is equivalent to open('/dev/null', write, Stream). Characters written to this stream are lost, but the stream information (see character count/2, etc.) is maintained.

close(+Stream)

Close the specified stream. If Stream is not open an error message is displayed. If the closed stream is the current input or output stream the terminal is made the current input or output.

current stream(?File, ?Mode, ?Stream)

Is true if a stream with file specification File, mode Mode and stream identifier Stream is open. The reserved streams user and user error are not generated by this predicate. If a stream has been opened with mode append this predicate will generate mode write.

stream position(+Stream, -Old, +New)

Unify the position parameters of Stream with Old and set them to New. A position is represented by the following term:

    '$stream_position'(CharNo, LineNo, LinePos).

It is only possible to change the position parameters if the stream is connected to a disk file. If the position is changed, the CharNo field determines the new position in the file. The LineNo and LinePos are copied in the stream administration.

3.13.3 Switching Between Implicit and Explicit I/O

The predicates below can be used for switching between the implicit- and the explicit stream based I/O predicates. set input(+Stream)

Set the current input stream to become Stream. Thus, open(file, read, Stream), set input(Stream) is equivalent to see(file).

set output(+Stream)

Set the current output stream to become Stream.

current input(-Stream)

Get the current input stream. Useful to get access to the status predicates associated with streams.

current output(-Stream)

Get the current output stream.

3.14 Status of Input and Output Streams

wait for input(+ListOfStreams, -ReadyList, +TimeOut)

Wait for input on one of the streams in ListOfStreams and return a list of streams on which input is available in ReadyList. wait for input/3 waits for at most TimeOut seconds. Timeout may be specified as a floating point number to specify fractions of a second. If Timeout equals 0, wait for input/3 waits indefinetely. This predicate can be used to implement timeout while reading and to handle input from multiple sources. The following example will wait for input from the user and an explicitely opened second terminal. On return, Inputs may hold user or P4 or both.

    ?- open('/dev/ttyp4', read, P4),
       wait_for_input([user, P4], Inputs, 0).

character count(+Stream, -Count)

Unify Count with the current character index. For input streams this is the number of characters read since the open, for output streams this is the number of characters written. Counting starts at 0.

line count(+Stream, -Count)

Unify Count with the number of lines read or written. Counting starts at 1.

line position(+Stream, -Count)

Unify Count with the position on the current line. Note that this assumes the position is 0 after the open. Tabs are assumed to be defined on each 8-th character and backspaces are assumed to reduce the count by one, provided it is positive.

fileerrors(-Old, +New)

Define error behaviour on errors when opening a file for reading or writing. Valid values are the atoms on (default) and off. First Old is unified with the current value. Then the new value is set to New.^{7}

7Note that Edinburgh Prolog defines fileerrors/0 and nofileerrors/0. As this does not allow you to switch back to the old mode I think this definition is better.

3.15 Primitive Character Input and Output

nl Write a newline character to the current output stream. On Unix systems nl/0 is equivalent

to put(10).

nl(+Stream)

Write a newline to Stream.

put(+Char)

Write Char to the current output stream, Char is either an integer-expression evaluating to an ASCII value (0 ≤ Char ≤ 255) or an atom of one character.

put(+Stream, +Char)

Write Char to Stream.

tab(+Amount)

Writes Amount spaces on the current output stream. Amount should be an expression that evaluates to a positive integer (see section 3.21).

tab(+Stream, +Amount)

Writes Amount spaces to Stream.

flush Flush pending output on current output stream. flush/0 is automatically generated by read/1 and derivates if the current input stream is user and the cursor is not at the left margin.

flush output(+Stream)

Flush output on the specified stream. The stream must be open for writing.

ttyflush Flush pending output on stream user. See also flush/0.

get0(-Char)

Read the current input stream and unify the next character with Char. Char is unified with -1 on end of file.

get0(+Stream, -Char)

Read the next character from Stream.

get(-Char)

Read the current input stream and unify the next non-blank character with Char. Char is unified with -1 on end of file.

get(+Stream, -Char)

Read the next non-blank character from Stream.

skip(+Char)

Read the input until Char or the end of the file is encountered. A subsequent call to get0/1 will read the first character after Char.

skip(+Stream, +Char)

Skip input (as skip/1) on Stream. get single char(-Char)

Get a single character from input stream ‘user’ (regardless of the current input stream). Unlike get0/1 this predicate does not wait for a return. The character is not echoed to the user’s terminal. This predicate is meant for keyboard menu selection etc.. If SWI-Prolog was started with the -tty flag this predicate reads an entire line of input and returns the first non-blank character on this line, or the ASCII code of the newline (10) if the entire line consisted of blank characters.

3.16 Term Reading and Writing

display(+Term)

Write Term on the current output stream using standard parenthesised prefix notation (i.e. ignoring operator declarations). Display is normally used to examine the internal representation for terms holding operators.

display(+Stream, +Term)

Display Term on Stream.

displayq(+Term)

Write Term on the current output stream using standard parenthesised prefix notation (i.e. ignoring operator declarations). Atoms that need quotes are quoted. Terms written with this predicate can always be read back, regardless of current operator declarations.

displayq(+Stream, +Term)

Display Term on Stream. Equivalent to Quintus write canonical/2.

write(+Term)

Write Term to the current output, using brackets and operators where appropriate.

write(+Stream, +Term)

Write Term to Stream.

writeq(+Term)

Write Term to the current output, using brackets and operators where appropriate. Atoms that need quotes are quoted. Terms written with this predicate can be read back with read/1 provided the currently active operator declarations are identical.

writeq(+Stream, +Term)

Write Term to Stream, inserting quotes.

print(+Term)

Prints Term on the current output stream similar to write/1, but for each (sub)term of Term first the dynamic predicate portray/1 is called. If this predicate succeeds print assumes the (sub)term has been written. This allows for user defined term writing.

print(+Stream, +Term)

Print Term to Stream.

portray(+Term)

A dynamic predicate, which can be defined by the user to change the behaviour of print/1 on (sub)terms. For each subterm encountered that is not a variable print/1 first calls portray/1 using the term as argument. For lists only the list as a whole is given to portray/1. If portray succeeds print/1 assumes the term has been written. read(-Term)

Read the next Prolog term from the current input stream and unify it with Term. On a syntax error read/1 displays an error message, attempts to skip the erroneous term and fails. On reaching end-of-file Term is unified with the atom end_of_file.

read(+Stream, -Term)

Read Term from Stream.

read clause(-Term)

Equivalent to read/1, but warns the user for variables only occurring once in a term (singleton variables) which do not start with an underscore if style check(singleton) is active (default). Used to read Prolog source files (see consult/1).

read clause(+Stream, -Term)

Read a clause from Stream.

read variables(-Term, -Bindings)

Similar to read/1, but Bindings is unified with a list of ‘Name = Var’ tuples, thus providing access to the actual variable names.

read variables(+Stream, -Term, -Bindings)

Read, returning term and bindings from Stream.

read history(+Show, +Help, +Special, +Prompt, -Term, -Bindings)

Similar to read variables/2, but allows for history substitutions. history read/6 is used by the top level to read the user’s actions. Show is the command the user should type to show the saved events. Help is the command to get an overview of the capabilities. Special is a list of commands that are not saved in the history. Prompt is the first prompt given. Continuation prompts for more lines are determined by prompt/2. A %w in the prompt is substituted by the event number. See section 2.4 for available substitutions.

SWI-Prolog calls history read/6 as follows:

    read_history(h, '!h', [trace], '%w ?- ', Goal, Bindings)

history depth(-Int)

Dynamic predicate, normally not defined. The user can define this predicate to set the history depth. It should unify the argument with a positive integer. When not defined 15 is used as the default.

prompt(-Old, +New)

Set prompt associated with read/1 and its derivates. Old is first unified with the current prompt. On success the prompt will be set to New if this is an atom. Otherwise an error message is displayed. A prompt is printed if one of the read predicates is called and the cursor is at the left margin. It is also printed whenever a newline is given and the term has not been terminated. Prompts are only printed when the current input stream is user.

3.17 Analysing and Constructing Terms

functor(?Term, ?Functor, ?Arity)

Succeeds if Term is a term with functor Functor and arity Arity. If Term is a variable it is unified with a new term holding only variables. functor/3 silently fails on instantiation faults^{8} If Term is an atom or number, Functor will be unified with Term and arity will be unified with the integer 0 (zero).

arg(?Arg, ?Term, ?Value)

Term should be instantiated to a term, Arg to an integer between 1 and the arity of Term. Value is unified with the Arg-th argument of Term. Arg may also be unbound. In this Value will be unified with the successive arguments of the term. On successfull unification, Arg is unified with the argument number. Backtracking yields alternative solutions.^{9}

setarg(+Arg, +Term, +Value)

Extra-logical predicate. Assigns the Arg-th argument of the compound term Term with the given Value. The assignment is undone if backtracking brings the state back into a position before the setarg/3 call.

This predicate may be used for destructive assignment to terms, using them as and extra-logical storage bin.

?Term =.. ?List List is a list which head is the functor of Term and the remaining arguments are the arguments of the term. Each of the arguments may be a variable, but not both. This predicate is called ‘Univ’. Examples:

     ?- foo(hello, X) =.. List.
     List = [foo, hello, X]
     ?- Term =.. [baz, foo(1)]
     Term = baz(foo(1))

numbervars(+Term, +Functor, +Start, -End)

Unify the free variables of Term with a term constructed from the atom Functor with one argument. The argument is the number of the variable. Counting starts at Start. End is unified with the number that should be given to the next variable. Example:

    ?- numbervars(foo(A, B, A), this_is_a_variable, 0, End).
    A = this_is_a_variable(0)
    B = this_is_a_variable(1)
    End = 2

In Edinburgh Prolog the second argument is missing. It is fixed to be '$VAR'.

free variables(+Term, -List)

Unify List with a list of variables, each sharing with a unique variable of Term. For example:

    ?- free_variables(a(X, b(Y, X), Z), L).
    L = [G367, G366, G371]
    X = G367

8In version 1.2 instantiation faults led to error messages. The new version can be used to do type testing without the need to catch illegal instantiations first.

9The instantion pattern (-, +, ?) is an extension to ‘standard’ Prolog.

    Y = G366
    Z = G371

copy term(+In, -Out)

Make a copy of term In and unify the result with Out. Ground parts of In are shared by Out. Provided In and Out have no sharing variables before this call they will have no sharing variables afterwards. copy term/2 is semantically equivalent to:

    copy_term(In, Out) :-
            recorda(copy_key, In, Ref),
            recorded(copy_key, Out, Ref),
            erase(Ref).

3.18 Analysing and Constructing Atoms

These predicates convert between Prolog constants and lists of ASCII values. The predicates atom chars/2, number chars/2 and number/2 behave the same when converting from a constant to a list of ASCII values. When converting the other way around, atom chars/2 will generate an atom, number chars will generate a number or fail and name/2 will return a number if possible and an atom otherwise.

atom chars(?Atom, ?String)

Convert between an atom and a list of ASCII values. If Atom is instantiated, if will be translated into a list of ASCII values and the result is unified with String. If Atom is unbound and String is a list of ASCII values, it will Atom will be unified with an atom constructed from this list.

atom char(?Atom, ?ASCII)

Convert between character and ASCII value for a single character.

number chars(?Number, ?String)

Similar to atom chars/2, but converts between a number and its representation as a list of ASCII values. Fails silently if Atom is unbound and String does not describe a number.

name(?AtomOrInt, ?String)

String is a list of ASCII values describing Atom. Each of the arguments may be a variable, but not both. When String is bound to an ASCII value list describing an integer and Atom is a variable Atom will be unified with the integer value described by String (e.g. ‘name(N, 300”), 400 is N + 100”’ succeeds).

int to atom(+Int, +Base, -Atom)

Convert Int to an ascii representation using base Base and unify the result with Atom. If Base ≠ 10 the base will be prepended to Atom. Base = 0 will try to interpret Int as an ASCII value and return 0'c. Otherwise 2 ≤ Base ≤ 36. Some examples are given below.

int to atom(45, 2, A)  ⟶  A = 2′101101
int to atom(97, 0, A)  ⟶  A = 0′a
int to atom(56, 10, A)  ⟶  A = 56

int to atom(+Int, -Atom)

     Equivalent to int_to_atom(Int, 10, Atom).

term to atom(?Term, ?Atom)

Succeeds if Atom describes a term that unifies with Term. When Atom is instantiated Atom is converted and then unified with Term. Otherwise Term is “written” on Atom using write/1.

atom to term(+Atom, -Term, -Bindings)

Use Atom as input to read variables/2 and return the read term in Term and the variable bindings in Bindings. Bindings is a list of Name = Var couples, thus providing access to the actual variable names. See also read variables/2.

concat(?Atom1, ?Atom2, ?Atom3)

Atom3 forms the concatenation of Atom1 and Atom2. At least two of the arguments must be instantiated to atoms, intergers or floating point numbers.

concat atom(+List, -Atom)

List is a list of atoms, integers or floating point numbers. Succeeds if Atom can be unified with the concatenated elements of List. If List has exactly 2 elements it is equivalent to concat/3, allowing for variables in the list.

atom length(+Atom, -Length)

Succeeds if Atom is an atom of Length characters long. This predicate also works for integers and floats, expressing the number of characters output when given to write/1.

3.19 Representing Text in Strings

SWI-Prolog supports the data type string. Strings are a time and space efficient mechanism to handle text in Prolog. Atoms are under some circumstances not suitable because garbage collection on them is next to impossible (Although it is possible: BIM prolog does it). Representing text as a list of ASCII values is, from the logical point of view, the cleanest solution. It however has two drawbacks: 1) they cannot be distinguished from a list of (small) integers; and 2) they consume (in SWI-Prolog) 12 bytes for each character stored.

Within strings each character only requires 1 byte storage. Strings live on the global stack and their storage is thus reclaimed on backtracking. Garbage collection can easily deal with strings.

The ISO standard proposes "..." is transformed into a string object by read/1 and derivates. This poses problems as in the old convention "..." is transformed into a list of ascii characters. For this reason the style check option ‘string’ is available (see style check/2).

The set of predicates associated with strings is incomplete and tentative. Names and definitions might change in the future to confirm to the emerging standard.

string to atom(?String, ?Atom)

Logical conversion between a string and an atom. At least one of the two arguments must be instantiated. Atom can also be an integer or floating point number.

string to list(?String, ?List)

Logical conversion between a string and a list of ASCII characters. At least one of the two arguments must be instantiated.

string length(+String, -Length)

Unify Length with the number of characters in String. This predicate is functonally equivalent to atom length/2 and also accepts atoms, integers and floats as its first argument. substring(+String, +Start, +Length, -Sub)

Create a substring of String that starts at character Start (1 base) and has Length characters. Unify this substring with Sub.^{10}

3.20 Operators

op(+Precedence, +Type, +Name)

Declare Name to be an operator of type Type with precedence Precedence. Name can also be a list of names, in which case all elements of the list are declared to be identical operators. Precedence is an integer between 0 and 1200. Precedence 0 removes the declaration. Type is one of: xf, yf, xfx, xfy, yfx, yfy, fy or fx. The ‘f’ indicates the position of the functor, while x and y indicate the position of the arguments. ‘y’ should be interpreted as “on this position a term with precedence lower or equal to the precedence of the functor should occur”. For ‘x’ the precedence of the argument must be strictly lower. The precedence of a term is 0, unless its principal functor is an operator, in which case the precedence is the precedence of this operator. A term enclosed in brackets ((...)) has precedence 0.

The predefined operators are shown in table 3.1. Note that all operators can be redefined by the user.

1200 xfx -->, :-
1200 fx :-, ?-

          1150 fx dynamic, multifile, module_transparent,
                     discontiguous, volatile, initialization

1100 xfy ;, |
1050 xfy ->
1000 xfy ,
954 xfy \\
900 fy \+, not
900 fx ~

           700 xfx {<, =, =.., =@=, =:=, =<, ==, =\=, >, >=, @<, @=<, \atop @>, @>=, \=, \==, is}

600 xfy :
500 yfx +, -, /\, \/, xor
500 fx +, -, ?, \
400 yfx *, /, //, <<, >>
300 xfx mod
200 xfy ^

Table 3.1: System operators

current op(?Precedence, ?Type, ?Name)

Succeeds when Name is currently defined as an operator of type Type with precedence Precedence. See also op/3.

10Future versions probably will provide a more logical variant of this predicate.

3.21 Arithmetic

Arithmetic can be divided into some special purpose integer predicates and a series of general predicates for floating point and integer arithmetic as appropriate. The integer predicates are as “logical” as possible. Their usage is recommended whenever applicable, resulting in faster and more “logical” programs.

The general arithmic predicates are optionaly compiled now (see please/3 and the -O command line option). Compiled arithmetic reduces global stack requirements and improves performance. Unfortunately compiled arithmetic cannot be traced, which is why it is optional.

The general arithmetic predicates all handle expressions. An expression is either a simple number or a function. The arguments of a function are expressions. The functions are described in section 3.22.

between(+Low, +High, ?Value)

Low and High are integers, High ≥ Low. If Value is an integer, Low ≤ Value ≤ High. When Value is a variable it is successively bound to all integers between Low and High.

succ(?Int1, ?Int2)

Succeeds if Int2 = Int1 + 1. At least one of the arguments must be instantiated to an integer.

plus(?Int1, ?Int2, ?Int3)

Succeeds if Int3 = Int1 + Int2 . At least two of the three arguments must be instantiated to integers.

+Expr1 > +Expr2 Succeeds when expression Expr1 evaluates to a larger number than Expr2.

+Expr1 < +Expr2 Succeeds when expression Expr1 evaluates to a smaller number than Expr2.

+Expr1 =< +Expr2 Succeeds when expression Expr1 evaluates to a smaller or equal number to Expr2.

+Expr1 >= +Expr2 Succeeds when expression Expr1 evaluates to a larger or equal number to Expr2.

+Expr1 =\= +Expr2 Succeeds when expression Expr1 evaluates to a number non-equal to Expr2.

+Expr1 =:= +Expr2 Succeeds when expression Expr1 evaluates to a number equal to Expr2.

-Number is +Expr Succeeds when Number has successfully been unified with the number Expr evaluates to.

3.22 Arithmetic Functions

Arithmetic functions are terms which are evaluated by the arithmetic predicates described above. SWI-Prolog tries to hide the difference between integer arithmetic and floating point arithmetic from the Prolog user. Arithmetic is done as integer arithmetic as long as possible and converted to floating point arithmetic whenever one of the arguments or the combination of them requires it. If a function returns a floating point value which is whole it is automatically transformed into an integer. There are three types of arguments to functions:

Expr Arbitrary expression, returning either a floating point value or an

integer.

IntExpr Arbitrary expression that should evaluate into an integer.
Int  An integer.

In case integer addition, subtraction and multiplication would lead to an integer overflow the operands are automatically converted to floating point numbers. The floating point functions (sin/1, exp/1, etc.) form a direct interface to the corresponding C library functions used to compile SWI-Prolog. Please refer to the C library documentation for details on percision, error handling, etc.

- +Expr Result = −Expr

+Expr1 + +Expr2 Result = Expr1 + Expr2

+Expr1 - +Expr2 Result = Expr1 − Expr2

+Expr1 * +Expr2 Result = Expr1 × Expr2

+Expr1 / +Expr2 Result = \frac{Expr1}{Expr2}

+IntExpr1 mod +IntExpr2 Result = Expr1 mod Expr2 (remainder of division).

+IntExpr1 // +IntExpr2 Result = Expr1 div Expr2 (integer division).

abs(+Expr)

Evaluate Expr and return the absolute value of it.

max(+Expr1, +Expr2)

Evaluates to the largest of both Expr1 and Expr2.

min(+Expr1, +Expr2)

Evaluates to the smallest of both Expr1 and Expr2.

.(+Int, [])

A list of one element evaluates to the element. This implies a”” evaluates to the ASCII value of the letter a (97). This option is available for compatibility only. It will not work if ‘style check(+string)’ is active as a”” will then be tranformed into a string object. The recommended way to specify the ASCII value of the letter ‘a’ is 0'a.

random(+Int)

Evaluates to a random integer i for which 0 ≤ i < Int. The seed of this random generator is determined by the system clock when SWI-Prolog was started.

integer(+Expr)

Evaluates Expr and rounds the result to the nearest integer.

floor(+Expr)

Evaluates Expr and returns the largest integer smaller or equal to the result of the evaluation. ceil(+Expr)

Evaluates Expr and returns the smallest integer larger or equal to the result of the evaluation.

+IntExpr >> +IntExpr Bitwise shift IntExpr1 by IntExpr2 bits to the right. Note that integers are only 27 bits.

+IntExpr << +IntExpr Bitwise shift IntExpr1 by IntExpr2 bits to the left.

+IntExpr \/ +IntExpr Bitwise ‘or’ IntExpr1 and IntExpr2.

+IntExpr /\ +IntExpr Bitwise ‘and’ IntExpr1 and IntExpr2.

+IntExpr xor +IntExpr Bitwise ‘exclusive or’ IntExpr1 and IntExpr2.

\ +IntExpr Bitwise negation.

sqrt(+Expr)

Result = \sqrt{Expr}

sin(+Expr)

Result = sin Expr. Expr is the angle in radials.

cos(+Expr)

Result = cos Expr. Expr is the angle in radials.

tan(+Expr)

Result = tan Expr. Expr is the angle in radials.

asin(+Expr)

Result = arcsin Expr. Result is the angle in radials.

acos(+Expr)

Result = arccos Expr. Result is the angle in radials.

atan(+Expr)

Result = arctan Expr. Result is the angle in radials.

atan(+YExpr, +XExpr)

Result = arctan \frac{YExpr}{XExpr} . Result is the angle in radials. The return value is in the range −π...π. Used to convert between rectangular and polar coordinate system.

log(+Expr)

Result = ln Expr

log10(+Expr)

Result = lg Expr

exp(+Expr)

Result = e^{Expr}

+Expr1 ^+Expr2 Result = Expr1^{Expr2} pi

Evaluates to the mathematical constant π (3.141593).

e Evaluates to the mathematical constant e (2.718282).

cputime Evaluates to a floating point number expressing the cpu time (in seconds) used by Prolog up till now. See also statistics/2 and time/1.

3.23 Adding Arithmetic Functions

Prolog predicates can be given the role of arithmetic function. The last argument is used to return the result, the arguments before the last are the inputs. Arithmetic functions are added using the predicate arithmetic function/1, which takes the head as its argument. Arithmetic functions are module sensitive, that is they are only visible from the module in which the function is defined and delared. Global arithmetic functions should be defined and registered from module user. Global definitions can be overruled locally in modules. The builtin functions described above can be redefined as well.

arithmetic function(+Head)

Register a Prolog predicate as an arithmetic function (see is/2, >/2, etc.). The Prolog predicate should have one more argument than specified by Head, which it either a term Name/Arity, an atom or a complex term. This last argument is an unbound variable at call time and should be instantiated to an integer or floating point number. The other arguments are the parameters. This predicate is module sensitive and will declare the arithmetic function only for the context module, unless declared from module user. Example:

          1 ?- [user].
          :- arithmetic_function(mean/2).
          mean(A, B, C) :-
                  C is (A+B)/2.
          user compiled, 0.07 sec, 440 bytes.
          Yes
          2 ?- A is mean(4, 5).
          A = 4.500000

current arithmetic function(?Head)

Succesively unifies all arithmetic functions that are visible from the context module with Head.

3.24 List Manipulation

is list(+Term)

Succeeds if Term is bound to the empty list ([]) or a term with functor ‘.’ and arity 2. proper list(+Term)

Equivalent to is list/1, but also requires the tail of the list to be a list (recursively). Examples:

    is_list([x|A])          % true
    proper_list([x|A])      % false

append(?List1, ?List2, ?List3)

Succeeds when List3 unifies with the concatenation of List1 and List2. The predicate can be used with any instantiation pattern (even three variables).

member(?Elem, ?List)

Succeeds when Elem can be unified with one of the members of List. The predicate can be used with any instantiation pattern.

memberchk(?Elem, +List)

Equivalent to member/2, but leaves no choice point.

delete(+List1, ?Elem, ?List2)

Delete all members of List1 that simultaneously unify with Elem and unify the result with List2.

select(?List1, ?Elem, ?List2)

Select an element of List1 that unifies with Elem. List2 is unified with the list remaining from List1 after deleting the selected element. Normally used with the instantiation pattern +List1, -Elem, -List2, but can also be used to insert an element in a list using -List1, +Elem, +List2.

nth0(?Index, ?List, ?Elem)

Succeeds when the Index-th element of List unifies with Elem. Counting starts at 0.

nth1(?Index, ?List, ?Elem)

Succeeds when the Index-th element of List unifies with Elem. Counting starts at 1.

last(?Elem, ?List)

Succeeds if Elem unifies with the last element of List.

reverse(+List1, -List2)

Reverse the order of the elements in List1 and unify the result with the elements of List2.

flatten(+List1, -List2)

Transform List1, possibly holding lists as elements into a ‘flat’ list by replacing each list with its elements (recursively). Unify the resulting flat list with List2. Example:

    ?- flatten([a, [b, [c, d], e]], X).
    X = [a, b, c, d, e]

length(?List, ?Int)

Succeeds if Int represents the number of elements of list List. Can be used to create a list holding only variables.

merge(+List1, +List2, -List3)

List1 and List2 are lists, sorted to the standard order of terms (see section 3.5). List3 will be unified with an ordered list holding the both the elements of List1 and List2. Duplicates are not removed.

3.25 Set Manipulation

is set(+Set)

Succeeds if Set is a proper list (see proper list/1) without duplicates.

list to set(+List, -Set)

Succeeds if Set holds the same elements as List in the same order, but has no duplicates. See

also sort/1.

intersection(+Set1, +Set2, -Set3)

Succeeds if Set3 unifies with the intersection of Set1 and Set2. Set1 and Set2 are lists without duplicates. They need not be ordered.

subtract(+Set, +Delete, -Result)

Delete all elements of set ‘Delete’ from ‘Set’ and unify the resulting set with ‘Result’.

union(+Set1, +Set2, -Set3)

Succeeds if Set3 unifies with the union of Set1 and Set2. Set1 and Set2 are lists without duplicates. They need not be ordered.

subset(+Subset, +Set)

Succeeds if all elements of Subset are elements of Set as well.

merge set(+Set1, +Set2, -Set3)

Set1 and Set2 are lists without duplicates, sorted to the standard order of terms. Set3 is unified with an ordered list without duplicates holding the union of the elements of Set1 and Set2.

3.26 Sorting Lists

sort(+List, -Sorted)

Succeeds if Sorted can be unified with a list holding the elements of List, sorted to the standard order of terms (see section 3.5). Duplicates are removed.

msort(+List, -Sorted)

Equivalent to sort/2, but does not remove duplicates.

keysort(+List, -Sorted)

List is a list of Key-Value pairs (e.g. terms of the functor ‘-’ with arity 2). keysort/2 sorts List like msort/2, but only compares the keys. Can be used to sort terms not on standard order, but on any criterion that can be expressed on a multi-dimensional scale. Sorting on more than one criterion can be done using terms as keys, putting the first criterion as argument 1, the second as argument 2, etc.

predsort(+Pred, +List, -Sorted)

Sorts similar to msort/2, but determines the order of two terms by applying Pred to pairs of elements from List (see apply/2). The predicate should succeed if the first element should be before the second.

3.27 Finding all Solutions to a Goal

findall(+Var, +Goal, -Bag)

Creates a list of the instantiations Var gets successively on backtracking over Goal and unifies the result with Bag. Succeeds with an empty list if Goal has no solutions. findall/3 is equivalent to bagof/3 with all free variables bound with the existence operator (^), except that bagof/3 fails when goal has no solutions.

bagof(+Var, +Goal, -Bag)

Unify Bag with the alternatives of Var, if Goal has free variables besides the one sharing with Var bagof will backtrack over the alternatives of these free variables, unifying Bag with the corresponding alternatives of Var. The construct Var^Goal tells bagof not to bind Var in Goal. Bagof/3 fails if Goal has no solutions.

The example below illustrates bagof/3 and the ^operator. The variable bindings are printed together on one line to save paper.

2 ?- listing(foo).
foo(a, b, c).
foo(a, b, d).
foo(b, c, e).
foo(b, c, f).
foo(c, c, g).
Yes
3 ?- bagof(C, foo(A, B, C), Cs).
A = a, B = b, C = G308, Cs = [c, d] ;
A = b, B = c, C = G308, Cs = [e, f] ;
A = c, B = c, C = G308, Cs = [g] ;
No
4 ?- bagof(C, A^foo(A, B, C), Cs).
A = G324, B = b, C = G326, Cs = [c, d] ;
A = G324, B = c, C = G326, Cs = [e, f, g] ;
No
5 ?-

setof(+Var, +Goal, -Set)

Equivalent to bagof/3, but sorts the result using sort/2 to get a sorted list of alternatives without duplicates.

3.28 Invoking Predicates on all Members of a List

All the predicates in this section call a predicate on all members of a list or until the predicate called fails. The predicate is called via apply/2, which implies common arguments can be put in front of the arguments obtained from the list(s). For example:

?- maplist(plus(1), [0, 1, 2], X).
X = [1, 2, 3]

we will phrase this as “Predicate is applied on ...”

checklist(+Pred, +List)

Pred is applied successively on each element of List until the end of the list or Pred fails. In the latter case the checklist/2 fails.

maplist(+Pred, ?List1, ?List2)

Apply Pred on all successive pairs of elements from List1 and List2. Fails if Pred can not be applied to a pair. See the example above.

sublist(+Pred, +List1, ?List2)

Unify List2 with a list of all elements of List1 to which Pred applies.

3.29 Forall

forall(+Cond, +Action)

For all alternative bindings of Cond Action can be proven. The example verifies that all arithmic statements in the list L are correct. It does not say which is wrong if one proves wrong.

          ?- forall(member(Result = Formula, [2 = 1 + 1, 4 = 2 * 2]),
                           Result =:= Formula).

3.30 Formatted Write

The current version of SWI-Prolog provides two formatted write predicates. The first is writef/[1,2], which is compatible with Edinburgh C-Prolog. The second is format/[1,2], which is compatible with Quintus Prolog. We hope the Prolog community will once define a standard formatted write predicate. If you want performance use format/[1,2] as this predicate is defined in C. Otherwise compatibility reasons might tell you which predicate to use.

3.30.1 Writef

write ln(+Term)

     Equivalent to write(Term), nl.

writef(+Atom)

     Equivalent to writef(Atom, []).

writef(+Format, +Arguments)

Formatted write. Format is an atom whose characters will be printed. Format may contain certain special character sequences which specify certain formatting and substitution actions. Arguments then provides all the terms required to be output.

Escape sequences to generate a single special character:

\n <NL> is output \l <LF> is output \r <CR> is output \t <TAB> is output \\ The character ‘\’ is output \% The character ‘%’ is output \nnn where nnn is an integer (1-3 digits) the character with

ASCII code nnn is output (NB : nnn is read as DECIMAL)

Escape sequences to include arguments from Arguments. Each time a % escape sequence is found in Format the next argument from Arguments is formatted according to the specification.

%t print/1 the next item (mnemonic: term) %w write/1 the next item %q writeq/1 the next item

%d   display/1 the next item

%p print/1 the next item (identical to %t) %n put the next item as a character (i.e. it is an ASCII value) %r write the next item N times where N is the second item

(an integer) %s write the next item as a String (so it must be a list of

characters) %f perform a ttyflush/0 (no items used) %Nc write the next item Centered in N columns. %Nl write the next item Left justified in N columns. %Nr write the next item Right justified in N columns. N is a

decimal number with at least one digit. The item must be an atom, integer, float or string.

swritef(-String, +Format, +Arguments)

Equivalent to writef/3, but “writes” the result on String instead of the current output stream. Example:

?- swritef(S, '%15L%w', ['Hello', 'World']).
S = "Hello          World"

swritef(-String, +Format)

Equivalent to swritef(String, Format, []).

3.30.2 Format

format(+Format)

Defined as ‘format(Format) :- format(Format, []).’

format(+Format, +Arguments)

Format is an atom, list of ASCII values, or a Prolog string. Arguments provides the arguments required by the format specification. If only one argument is required and this is not a list of ASCII values the argument need not be put in a list. Otherwise the arguments are put in a list.

Special sequences start with the tilde (~), followed by an optional numeric argument, followed by a character describing the action to be undertaken. A numeric argument is either a sequence of digits, representing a positive decimal number, a sequence `<character>, representing the ASCII value of the character (only useful for ~t) or a asterisk (*), in when the numeric argument is taken from the next argument of the argument list, which should be a positive integer. Actions are:

˜ Output the tilde itself.

a Output the next argument, which should be an atom. This option is equivalent to w. Compatibility reasons only.

c Output the next argument as an ASCII value. This argument should be an integer in the range [0, ..., 255] (including 0 and 255).

d Output next argument as a decimal number. It should be an integer. If a numeric argument is specified a dot is inserted argument positions from the right (useful for doing fixed point arithmetic with integers, such as handling amounts of money).

D Same as d, but makes large values easier to read by inserting a comma every three digits left to the dot or right.

e Output next argument as a floating point number in exponentional notation. The numeric argument specifies the precission. Default is 6 digits. Exact representation depends on the C library function printf(). This function is invoked with the format %.<percission>e.

E Equivalent to e, but outputs a capital E to indicate the exponent.

f Floating point in non-exponentional notation. See C library function printf().

g Floating point in e or f notation, whichever is shorter.

G Floating point in E or f notation, whichever is shorter.

i Ignore next argument of the argument list. Produces no output.

k Give the next argument to displayq/1 (canonical write).

n Output a newline character.

N Only output a newline if the last character output on this stream was not a newline. Not properly implemented yet.

p Give the next argument to print/1.

q Give the next argument to writeq/1.

r Print integer in radix the numeric argument notation. Thus ~16r prints its argument hexadecimal. The argument should be in the range [2, ... 36]. Lower case letters are used for digits above 9.

R Same as r, but uses upper case letters for digits above 9.

s Output a string of ASCII characters from the next argument.

t All remaining space between 2 tabstops is distributed equaly over ~t statements between the tabstops. This space is padded with spaces by default. If an argument is supplied this is taken to be the ASCII value of the character used for padding. This can be used to do left or right alignment, centering, distributing, etc. See also ~| and ~+ to set tab stops. A tabstop is assumed at the start of each line.

Set a tabstop on the current position. If an argument is supplied set a tabstop on the position of that argument. This will cause all ~t’s to be distributed between the previous and this tabstop.

+ Set a tabstop relative to the current position. Further the same as ~|.

w Give the next argument to write/1.

Example:

     simple_statistics :-
         <obtain statistics>         % left to the user
         format('~tStatistics~t~72|~n~n'),
         format('Runtime: ~`.t ~2f~34|  Inferences: ~`.t ~D~72|~n',
                                                 [RunT, Inf]),
         ....

Will output

                                  Statistics
     Runtime: .................. 3.45  Inferences: .......... 60,345

sformat(-String, +Format, +Arguments)

Equivalent to format/3, but “writes” the result on String instead of the current output stream. Example:

    ?- sformat(S, '~w~t~15|~w', ['Hello', 'World']).
    S = "Hello          World"

sformat(-String, +Format)

Equivalent to ‘sformat(String, Format, []).’

3.30.3 Programming Format

format predicate(+Char, +Head)

If a sequence ~c (tilde, followed by some character) is found, the format derivates will first check whether the user has defined a predicate to handle the format. If not, the built in formatting rules described above are used. Char is either an ascii value, or a one character atom, specifying the letter to be (re)defined. Head is a term, whose name and arity are used to determine the predicate to call for the redefined formatting character. The first argument to the predicate is the numeric argument of the format command, or the atom default if no argument is specified. The remaining arguments are filled from the argument list. The example below redefines ~n to produce Arg times return followed by linefeed (so a (Grr.) DOS machine is happy with the output).

     :- format_predicate(n, dos_newline(_Arg)).
     dos_newline(Arg) :-
             between(1, Ar, _), put(13), put(10), fail ; true.

3.31 Terminal Control

The following predicates form a simple access mechanism to the Unix termcap library to provide terminal independant I/O for screen terminals. The library package tty builds on top of these predicates.

tty get capability(+Name, +Type, -Result)

Get the capability named Name from the termcap library. See termcap(5) for the capability names. Type specifies the type of the expected result, and is one of string, number or bool. String results are returned as an atom, number result as an integer and bool results as the atom on or off. If an option cannot be found this predicate fails silently. The results are only computed once. Succesive queries on the same capability are fast.

tty goto(+X, +Y)

Goto position (X, Y) on the screen. Note that the predicates line count/2 and line position/2 will not have a well defined behaviour while using this predicate.

tty put(+Atom, +Lines)

Put an atom via the termcap library function tputs(). This function decodes padding information in the strings returned by tty get capability/3 and should be used to output these strings. Lines is the number of lines affected by the operation, or 1 if not applicable (as in almost all cases).

set tty(-OldStream, +NewStream)

Set the output stream, used by tty put/2 and tty goto/2 to a specific stream. Default is user output.

3.32 Unix Interaction

shell(+Command, -Status)

Execute Command on the operating system. Command is given to the bourne shell (/bin/sh). Status is unified with the exit status of the command.

shell(+Command)

Equivalent to ‘shell(Command, 0)’.

shell Start an interactive Unix shell. Default is /bin/sh, the environment variable SHELL overrides this default.

getenv(+Name, -Value)

Get Unix environment variable (see csh(1) and sh(1)). Fails if the variable does not exist.

setenv(+Name, +Value)

Set Unix environment variable. Name and Value should be instantiated to atoms or integers. The environment variable will be passed to shell/[0-2] and can be requested using getenv/2.

unsetenv(+Name)

Remove Unix environment variable from the environment.

get time(-Time)

Return the number of seconds that elapsed since the epoch of Unix, 1 January 1970, 0 hours. Time is a floating point number. Its granularity is system dependant. On SUN, this is 1/60 of a second. convert time(+Time, -Year, -Month, -Day, -Hour, -Minute, -Second, -MilliSeconds)

Convert a time stamp, provided by get time/1, file time/2, etc. Year is unified with the year, Month with the month number (January is 1), Day with the day of the month (starting with 1), Hour with the hour of the day (0–23), Minute with the minute (0–59). Second with the second (0–59) and MilliSecond with the milli seconds (0–999). Note that the latter might not be acurate or might always be 0, depending on the timing capabilities of the system.

3.33 File System Interaction

access file(+File, +Mode)

Succeeds when File exists and can be accessed by this prolog process under mode Mode. Mode is one of the atoms read, write, append, exist, none or execute. File may also be the name of a directory. Fails silently otherwise. access file(File, none) simply succeeds without testing anything.

exists file(+File)

Succeeds when File exists. This does not imply the user has read and/or write permission for the file.

file directory name(+File, -Directory)

Extracts the directory-part of File. The resulting Directory name ends with the directory separator character /. If File is an atom that does not contain any directory separator characters, the empty atom '' is returned. See also file base name/2.

file base name(+File, -BaseName)

Extracts the filename part from a path specification. If File does not contain any directory separators, File is returned.

same file(+File1, +File2)

Succeeds if both filenames refer to the same physical file. That is, if File1 and File2 are the same string or both names exist and point to the same file (due to hard or symbolic links and/or relative vs. absolute paths).

exists directory(+Directory)

Succeeds if Directory exists. This does not imply the user has read, search and or write permission for the directory.

delete file(+File)

Unlink File from the Unix file system.

rename file(+File1, +File2)

Rename File1 into File2. Currently files cannot be moved across devices.

size file(+File, -Size)

Unify Size with the size of File in characters.

time file(+File, -Time)

Unify the last modification time of File with Time. Time is a floating point number expressing the seconds elapsed since Jan 1, 1970.

absolute file name(+File, -Absolute)

Expand Unix file specification into an absolute path. User home directory expansion (~ and ~user) and variable expansion is done. The absolute path is canonised: references to ‘.’ and ‘..’ are deleted. SWI-Prolog uses absolute file names to register source files independant of the current working directory.

absolute file name(+Spec, +Options, -Absolute)

Converts the given file specification into an absolute path. Option is a list of options to guide the conformation process:

    extensions(ListOfExtensions)

List of file-extensions to try. Default is ['']. For each extension, absolute file name/3 will first add the extension and then verify the conditions imposed by the other options. If the condition fails, the next extension of the list is tried. Extensions may be specified both as '.ext' or plain 'ext'.

    access(Mode)

Imposes the condition access file(File, Mode). Mode is on of read, write,

        append, exist or none. See also access file/2.

is absolute file name(+File)

True if File specifies and absolute path-name. On Unix systems, this implies the path starts with a ‘/’. For MicroSoft based systems this implies the path starts with <letter>:. This predicate is intended to provide platform-independent checking for absolute paths. See also

absolute file name/2 and prolog to os filename/2.

expand file name(+WildChart, -List)

Unify List with a sorted list of files or directories matching WildChart. The normal Unix wildchart constructs ‘?’, ‘*’, ‘[...]’ and ‘{...}’ are recognised. The interpretation of ‘{...}’ is interpreted slightly different from the C shell (csh(1)). The comma separated argument can be arbitrary patterns, including ‘{...}’ patterns. The empty pattern is legal as well: ‘{.pl,}’ matches either ‘.pl’ or the empty string.

prolog to os filename(?PrologPath, ?OsPath)

Converts between the internal Prolog pathname conventions and the operating-system pathname conventions. The internal conventions are Unix and this predicates is equivalent to =/2 (unify) on Unix systems. On DOS systems it will change the directory-separator, limit the filename length map dots, except for the last one, onto underscores.

read link(+File, -Link, -Target)

If File points to a symbolic link, unify Link with the value of the link and Target to the file the link is pointing to. Target points to a file, directory or non-existing entry in the file system, but never to a link. Fails if File is not a link. Fails always on systems that donot support symbolic links.

tmp file(+Base, -TmpName)

Create a name for a temporary file. Base is an identifier for the category of file. The TmpName is guaranteed to be unique. If the system halts, it will automatically remove all created temporary files.

chdir(+Path)

Change working directory to Path.

3.34 User Toplevel Manipulation

break Recursively start a new Prolog top level. This Prolog top level has it’s own stacks, but shares the heap with all break environments and the top level. Debugging is switched off on entering a break and restored on leaving one. The break environment is terminated by typing the system’s end-of-file character (control-D). If the -t toplevel command line option is given this goal is started instead of entering the default interactive top level (prolog/0).

abort Abort the Prolog execution and start a new top level. If the -t toplevel command line options is given this goal is started instead of entering the default interactive top level. Break environments are aborted as well. All open files except for the terminal related files are closed. The input- and output stream again refers to user.^{11}

halt Terminate Prolog execution. Open files are closed and if the command line option -tty is not active the terminal status (see Unix stty(1)) is restored. Hooks may be registered both in Prolog and in foreign code. Prolog hooks are registered using at halt/1. halt/0 is equivalent to halt(0).

halt(+Status)

Terminate Prolog execution with given status. Status is an integer. See also halt/0.

prolog This goal starts the default interactive top level. prolog/0 is terminated (succeeds) by typing control-D.

3.35 Creating a Protocol of the User Interaction

SWI-Prolog offers the possibility to log the interaction with the user on a file.^{12} All Prolog interaction, including warnings and tracer output, are written on the protocol file.

protocol(+File)

Start protocolling on file File. If there is already a protocol file open then close it first. If File exists it is truncated.

protocola(+File)

Equivalent to protocol/1, but does not truncate the File if it exists.

noprotocol Stop making a protocol of the user interaction. Pending output is flushed on the file.

protocolling(-File)

Succeeds if a protocol was started with protocol/1 or protocola/1 and unifies File with the current protocol output file.

3.36 Debugging and Tracing Programs

trace Start the tracer. trace/0 itself cannot be seen in the tracer. Note that the Prolog toplevel treats trace/0 special; it means ‘trace the next goal’. tracing

11BUG: Erased clauses which could not actually be removed from the database, because they are active in the interpreter, will never be garbage collected after an abort.

12A similar facility was added to Edinburgh C-Prolog by Wouter Jansweijer.

Succeeds when the tracer is currently switched on. tracing/0 itself can not be seen in the tracer.

notrace Stop the tracer. notrace/0 itself cannot be seen in the tracer.

trace(+Pred)

Equivalent to trace(Pred, +all).

trace(+Pred, +Ports)

Put a trace-point on all predicates meeting the predicate specification Pred. Ports is a list of portnames (call, redo, exit, fail). The atom all refers to all ports. If the port is predeced by a ‘-’ sign the trace-point is cleared for the port. If it is predeced by a ‘+’ the trace-point is set.

The predicate trace/2 activates debug mode (see debug/0). Each time a port (of the 4-port model) is passed that has a trace-point set the goal is printed as with trace/0. Unlike trace/0 however, the execution is continued without asking for further information. Examples:

?- trace(hello). Trace all ports of hello with any arity in any

module.

?- trace(foo/2, +fail) Trace failures of foo/2 in any module.

      ?- trace(bar/1, -all) Stop tracing bar/1.

The predicate debugging/0 shows all currently defined trace-points.

debug Start debugger (stop at spy points).

nodebug Stop debugger (do not trace, nor stop at spy points).

debugging Print debug status and spy points on current output stream.

spy(+Pred)

Put a spy point on all predicates meeting the predicate specification Pred. See section 3.3.

nospy(+Pred)

Remove spy point from all predicates meeting the predicate specification Pred.

nospyall Remove all spy points from the entire program.

leash(?Ports)

Set/query leashing (ports which allow for user interaction). Ports is one of +Name, -Name, ?Name or a list of these. +Name enables leashing on that port, -Name disables it and ?Name succeeds or fails according to the current setting. Recognised ports are: call, redo, exit, fail and unify. The special shorthand all refers to all ports, full refers to all ports except for the unify port (default). half refers to the call, redo and fail port.

visible(+Ports)

Set the ports shown by the debugger. See leash/1 for a description of the port specification. Default is full. unknown(-Old, +New)

Unify Old with the current value of the unknown system flag. On success New will be used to specify the new value. New should be instantiated to either fail or trace and determines the interpreter’s action when an undefined predicate which is not declared dynamic is encountered (see dynamic/1). fail implies the predicate just fails silently. trace implies the tracer is started. Default is trace. The unknown flag is local to each module and unknown/2 is module transparent. Using it as a directive in a module file will only change the unknown flag for that module. Using the :/2 construct the behaviour on trapping an undefined predicate can be changed for any module. Note that if the unknown flag for a module equals fail the system will not call exception/3 and will not try to resolve the predicate via the dynamic library system. The system will still try to import the predicate from the public module.

style check(+Spec)

Set style checking options. Spec is either +<option>, -<option>, ?<option> or a list of such options. +<option> sets a style checking option, -<option> clears it and ?<option> succeeds or fails according to the current setting. consult/1 and derivates resets the style checking options to their value before loading the file. If –for example– a file containing long atoms should be loaded the user can start the file with:

    :- style_check(-atom).

Currently available options are:

Name  Default Description

   singleton

on read clause/1 (used by consult/1) warns on variables only appearing once in a term (clause) which have a name not starting with an underscore.

   atom

on read/1 and derivates will produce an error message on

quoted atoms or strings longer than 5 lines.

   dollar

off Accept dollar as a lower case character, thus avoiding the need for quoting atoms with dollar signs. System maintenance use only.

discontiguous on Warn if the clauses for a predicate are not together in the

same source file.

   string

off Read and derivates transform "..." into a prolog string instead of a list of ASCII characters.

3.37 Obtaining Runtime Statistics

statistics(+Key, -Value)

Unify system statistics determined by Key with Value. The possible keys are given in the table 3.2.

statistics Display a table of system statistics on the current output stream.

time(+Goal)

Execute Goal just like once/1 (i.e. leaving no choice points), but print used time, number of logical inferences and the average number of lips (logical inferences per second). Note that SWI-Prolog counts the actual executed number of inferences rather than the number of passes through the call- and redo ports of the theoretical 4-port model. cputime (User) cpu time since Prolog was started in seconds inferences Total number of passes via the call and redo ports since Prolog was

started.

heapused Bytes heap in use. local Allocated size of the local stack in bytes. localused Number of bytes in use on the local stack. locallimit Size to which the local stack is allowed to grow global Allocated size of the global stack in bytes. globalused Number of bytes in use on the global stack. globallimit Size to which the global stack is allowed to grow trail Allocated size of the trail stack in bytes. trailused Number of bytes in use on the trail stack. traillimit Size to which the trail stack is allowed to grow atoms Total number of defined atoms. functors Total number of defined name/arity pairs. predicates Total number of predicate definitions. modules Total number of module definitions. externals Total number of external references in all clauses. codes Total amount of byte codes in all clauses.

Table 3.2: Keys for statistics/2

3.38 Finding Performance Bottlenecks

SWI-Prolog offers a statistical program profiler similar to Unix prof(1) for C and some other languages. A profiler is used as an aid to find performance pigs in programs. It provides information on the time spent in the various Prolog predicates.

The profiler is based on the assumption that if we monitor the functions on the execution stack on time intervals not correlated to the program’s execution the number of times we find a procedure on the environment stack is a measure of the time spent in this procedure. It is implemented by calling a procedure each time slice Prolog is active. This procedure scans the local stack and either just counts the procedure on top of this stack (plain profiling) or all procedures on the stack (cummulative profiling). To get accurate results each procedure one is interested in should have a reasonable number of counts. Typically a minute runtime will suffice to get a rough overview of the most expensive procedures.

profile(+Goal, +Style, +Number)

Execute Goal just like time/1. Collect profiling statistics according to style (see profiler/2) and show the top Number procedures on the current output stream (see show profile/1). The results are kept in the database until reset profiler/0 or profile/3 is called and can be displayed again with show profile/1. profile/3 is the normal way to invoke the profiler. The predicates below are low-level predicates that can be used for special cases.

show profile(+Number)

Show the collected results of the profiler. Stops the profiler first to avoid interference from show profile/1. It shows the top Number predicates according the percentage cpu-time used^{13}. profiler(-Old, +New)

13show profile/1 is defined in Prolog and takes a considerable amount of memory.

Query or change the status of the profiler. The status is one of off, plain or cummulative. plain implies the time used by children of a predicate is not added to the time of the predicate. For status cummulative the time of childs is added (except for recursive calls). Cummulative profiling implies the stack is scanned upto the top on each time slice to find all active predicates. This implies the overhead grows with the number of active frames on the stack. Cummulative profiling starts debugging mode to disable tail recursion optimisation, which would otherwise remove the necessary parent environments. Switching status from plain to cummulative resets the profiler. Switching to and from status off does not reset the collected statistics, thus allowing to suspend profiling for certain parts of the program.

reset profiler Switches the profiler to off and clears all collected statistics.

profile count(+Head, -Calls, -Promilage)

Obtain profile statistics of the predicate specified by Head. Head is an atom for predicates with arity 0 or a term with the same name and arity as the predicate required (see current predicate/2). Calls is unified with the number of ‘calls’ and ‘redos’ while the profiler was active. Promilage is unified with the relative number of counts the predicate was active (cummulative) or on top of the stack (plain). Promilage is an integer between 0 and 1000.

3.39 Memory Management

Note: limit stack/2 and trim stacks/0 have no effect on machines that do not offer dynamic stack expansion. On these machines these predicates simply succeed to improve portability.

garbage collect Invoke the global- and trail stack garbage collector. Normally the garbage collector is invoked automatically if necessary. Explicit invokation might be useful to reduce the need for garbage collections in time critical segments of the code. After the garbage collection trim stacks/0 is invoked to release the collected memory resources.

limit stack(+Key, +Kbytes)

Limit one of the stack areas to the specified value. Key is one of local, global or trail. The limit is an integer, expressing the desired stack limit in K bytes. If the desired limit is smaller than the currently used value, the limit is set to the nearest legal value above the currently used value. If the desired value is larger than the maximum, the maximum is taken. Finally, if the desired value is either 0 or the atom unlimited the limit is set to its maximum. The maximum and initial limit is determined by the command line options -L, -G and -T.

trim stacks Release stack memory resources that are not in use at this moment, returning them to the operating system. Trim stack is a relatively cheap call. It can be used to release memory resources in a backtracking loop, where the iterations require typically seconds of execution time and very different, potentionally large, amounts of stack space. Such a loop should be written as follows:

          loop :-
                  generator,
                      trim_stacks,
                      potentionally_expensive_operation,
                  stop_condition, !.

The prolog top level loop is written this way, reclaiming memory resources after every user query.

stack parameter(+Stack, +Key, -Old, +New)

Query/set a parameter for the runtime stacks. Stack is one of local, global, trail, argument or lock. The table below describes the Key/Value pairs. Old is first unified with the current value.

limit  Maximum size of the stack in bytes
min free Minimum free space at entry of foreign predicate

This predicate is currently only available on versions that use the stack-shifter to enlarge the runtime stacks when necessary. It’s definition is subject to change.

3.40 Windows DDE interface

The predicates in this section deal with MS-Windows ‘Dynamic Data Exchange’ or DDE protocol.^{14} A Windows DDE conversation is a form of interprocess communication based on sending reserved window-events between the communicating processes.

See also section 5.4 for loading Windows DLL’s into SWI-Prolog.

3.40.1 DDE client interface

The DDE client interface allows Prolog to talk to DDE server programs. We will demonstrate the use of the DDE interface using the Windows PROGMAN (Program Manager) application:

     1 ?- open_dde_conversation(progman, progman, C).
     C = 0
     2 ?- dde_request(0, groups, X)
     --> Unifies X with description of groups
     3 ?- dde_execute(0, '[CreateGroup("DDE Demo")]').
     Yes
     4 ?- close_dde_conversation(0).
     Yes

14This interface is contributed by Don Dwiggins.

For details on interacting with PROGMAN, use the SDK online manual section on the Shell DDE interface. See also the Prolog library progman.pl, which may be used to write simple Windows setup scripts in Prolog.

open dde conversation(+Service, +Topic, -Handle)

Open a conversation with a server supporting the given service name and topic (atoms). If successful, Handle may be used to send transactions to the server. If no willing server is found this predicate fails silently.

close dde conversation(+Handle)

Close the conversation associated with Handle. All opened conversations should be closed when they’re no longer needed, although the system will close any that remain open on process termination.

dde request(+Handle, +Item, -Value)

Request a value from the server. Item is an atom that identifies the requested data, and Value will be an atom (CF TEXT data in DDE parlance) representing that data, if the request is successful. If unsuccessful, Value will be unified with a term of form error(reason), identifying the problem.^{15}

dde execute(+Handle, +Command)

Request the DDE server to execute the given command-string. Succeeds if the command could be executed and fails with error message otherwise.

3.40.2 DDE server mode

The (autoload) library dde.pl defines primitives to realise simple DDE server applications in SWI-Prolog. These features are provided as of version 2.0.6 and should be regarded prototypes. The C-part of the DDE server can handle some more primitives, so if you need features not provided by this interface, please study the library dde.pl.

dde register service(+Template, +Goal)

Register a server to handle DDE request or DDE execute requests from other applications. To register a service for a DDE request, Template is of the form:

+Service(+Topic, +Item, +Value)

Service is the name of the DDE service provided (like progman in the client example above). Topic is either an atom, indicating Goal only handles requests on this topic or a variable that also appears in Goal. Item and Value are variables that also appear in Goal. The example below registers the Prolog feature/2 predicate to be accessible from other applications. The request may be given from the same Prolog as well as from another application.

     ?- dde_register_service(prolog(feature, F, V),
                             feature(F, V)).
     ?- open_dde_conversation(prolog, feature, Handle),
        dde_request(Handle, home, Home),
        close_dde_conversation(Handle).
     Home = '/usr/local/lib/pl-2.0.6/'

15BUG: It could be argued that the atoms above should be strings.

Handling DDE execute requests is very similar. In this case the template is of the form:

+Service(+Topic, +Item)

Passing a Value argument is not needed as execute requests either succeed or fail. If Goal fails, a ‘not processed’ is passed back to the caller of the DDE request.

dde unregister service(+Service)

Stop responding to Service. If Prolog is halted, it will automatially call this on all open services.

dde current service(-Service, -Topic)

Find currently registered services and the topics served on them.

dde current connection(-Service, -Topic)

Find currently open conversations.

3.41 Miscellaneous

dwim match(+Atom1, +Atom2)

Succeeds if Atom1 matches Atom2 in ‘Do What I Mean’ sence. Both Atom1 and Atom2 may also be integers or floats. The two atoms match if:

• They are identical

• They differ by one character (spy ≡ spu)

• One character is insterted/deleted (debug ≡ deug)

• Two characters are transposed (trace ≡ tarce)

• ‘Sub-words’ are glued differently (existsfile ≡ existsFile ≡ exists file)

• Two adjacent sub words are transposed (existsFile ≡ fileExists)

dwim match(+Atom1, +Atom2, -Difference)

Equivalent to dwim match/2, but unifies Difference with an atom identifying the the difference between Atom1 and Atom2. The return values are (in the same order as above): equal,

mismatched char, inserted char, transposed char, separated and transposed word.

wildcard match(+Pattern, +String)

Succeeds if String matches the wildcard pattern Pattern. Pattern is very similar the the Unix csh pattern matcher. The patterns are given below:

?  Matches one arbitrary character
*  Matches any number of arbitrary characters
[...] Matches one of the characters specified at ... <char>-<char> indicates a range.
{...} Matches any of the patterns of the comma separated list between the brackets.

Example:

    ?- wildcard_match('[a-z]*.{pro,pl}[%~]', 'a_hello.pl%').
    Yes.

gensym(+Base, -Unique)

Generate a unique atom from base Base and unify it with Unique. Base should be an atom. The first call will return <base>1, the next <base>2, etc. Note that this is no warrant that the atom is unique in the system.^{16} sleep(+Time)

16BUG: I plan to supply a real gensym/2 which does give this warrant for future versions.

Suspend execution Time seconds. Time is either a floating point number or an integer. Granularity is dependent on the system’s timer granularity (1/60 seconds on most Unix systems). A negative time causes the timer to return immediately. As Unix is a multi-tasking environment we can only ensure execution is suspended for at least Time seconds.

CHAPTER 3. BUILT-IN PREDICATES 2.1 – 74 –

Using Modules

4.1 Why Using Modules?

In traditional Prolog systems the predicate space was flat. This approach is not very suitable for the development of large applications, certainly not if these applications are developed by more than one programmer. In many cases, the definition of a Prolog predicate requires sub-predicates that are intented only to complete the definition of the main predicate. With a flat and global predicate space these support predicates will be visible from the entire program.

For this reason, it is desirable that each source module has it’s own predicate space. A module consists of a declaration for it’s name, it’s public predicates and the predicates themselves. This approach allow the programmer to use short (local) names for support predicates without worrying about name conflicts with the support predicates of other modules. The module declaration also makes explicit which predicates are meant for public usage and which for private purposes. Finally, using the module information, cross reference programs can indicate possible problems much better.

4.2 Name-based versus Predicate-based Modules

Two approaches to realise a module system are commonly used in Prolog and other languages. The first one is the name based module system. In these systems, each atom read is tagged (normally prefixed) with the module name, with the exception of those atoms that are defined public. In the second approach, each module actually implements its own predicate space.

A critical problem with using modules in Prolog is introduced by the meta-predicates that transform between Prolog data and Prolog predicates. Consider the case where we write:

     :- module(extend, [add_extension/3]).
     add_extension(Extension, Plain, Extended) :-
             maplist(extend_atom(Extension), Plain, Extended).
     extend_atom(Extension, Plain, Extended) :-
             concat(Plain, Extension, Extended).

CHAPTER 4. USING MODULES 2.1

In this case we would like maplist to call extend atom/3 in the module extend. A name based module system will do this correctly. It will tag the atom extend atom with the module and maplist will use this to construct the tagged term extend atom/3. A name based module however, will not only tag the atoms that will eventually be used to refer to a predicate, but all atoms that are not declared public. So, with a name based module system also data is local to the module. This introduces another serious problem:

     :- module(action, [action/3]).
     action(Object, sleep, Arg) :- ....
     action(Object, awake, Arg) :- ....
     :- module(process, [awake_process/2]).
     awake_process(Process, Arg) :-
             action(Process, awake, Arg).

This code uses a simple object-oriented implementation technique were atoms are used as method selectors. Using a name based module system, this code will not work, unless we declare the selectors public atoms in all modules that use them. Predicate based module systems do not require particular precautions for handling this case.

It appears we have to choose either to have local data, or to have trouble with meta-predicates. Probably it is best to choose for the predicate based approach as novice users will not often write generic meta-predicates that have to be used across multiple modules, but are likely to write programs that pass data around across modules. Experienced Prolog programmers should be able to deal with the complexities of meta-predicates in a predicate based module system.

4.3 Defining a Module

Modules normally are created by loading a module file. A module file is a file holding a module/2 directive as its first term. The module/2 directive declares the name and the public (i.e. externally visible) predicates of the module. The rest of the file is loaded into the module. Below is an example of a module file, defining reverse/2.

     :- module(reverse, [reverse/2]).
     reverse(List1, List2) :-
             rev(List1, [], List2).
     rev([], List, List).
     rev([Head|List1], List2, List3) :-
             rev(List1, [Head|List2], List3).

4.4 Importing Predicates into a Module

As explained before, in the predicate based approach adapted by SWI-Prolog, each module has it’s own predicate space. In SWI-Prolog, a module initially is completely empty. Predicates can be added to a module by loading a module file as demonstrated in the previous section, using assert or by importing them from another module.

Two mechanisms for importing predicates explicitely from another module exist. The use module/[1,2] predicates load a module file and import (part of the) public predicates of the file. The import/1 predicate imports any predicate from any module.

use module(+File)

Load the file(s) specified with File just like ensure loaded/1. The files should all be module files. All exported predicates from the loaded files are imported into the context module. The difference between this predicate and ensure loaded/1 becomes apparent if the file is already loaded into another module. In this case ensure loaded/1 does nothing; use module will import all public predicates of the module into the current context module.

use module(+File, +ImportList)

Load the file specified with File (only one file is accepted). File should be a module file. ImportList is a list of name/arity pairs specifying the predicates that should be imported from the loaded module. If a predicate is specified that is not exported from the loaded module a warning will be printed. The predicate will nevertheless be imported to simplify debugging.

import(+Head)

Import predicate Head into the current context module. Head should specify the source module using the <module>:<term> construct. Note that predicates are normally imported using one of the directives use module/[1,2]. import/1 is meant for handling imports into dynamically created modules.

It would be rather inconvient to have to import each predicate refered to by the module, including the system predicates. For this reason each module is assigned a default module. All predicates in the default module are available without extra declarations. Their definition however can be overruled in the local module. This schedule is implemented by the exception handling mechanism of SWI-Prolog: if an undefined predicate exception is raised for a predicate in some module, the exception handler first tries to import the predicate from the module’s default module. On success, normal execution is resumed.

4.4.1 Reserved Modules

SWI-Prolog contains two special modules. The first one is the module system. This module contains all built-in predicates described in this manual. Module system has no default module assigned to it. The second special module is the module user. This module forms the initial working space of the user. Initially it is empty. The default module of module user is system, making all built-in predicate definitions available as defaults. Built-in predicates thus can be overruled by defining them in module user before they are used.

All other modules default to module user. This implies they can use all predicates imported into user without explicitely importing them.

4.5 Using the Module System

The current structure of the module system has been designed with some specific organisations for large programs in mind. Many large programs define a basic library layer on top of which the actual program itself is defined. The module user, acting as the default module for all other modules of the program can be used to distribute these definitions over all program module without introducing the need to import this common layer each time explicitely. It can also be used to redefine builtin predicates if this is required to maintain compatibility to some other Prolog implementation. Typically, the loadfile of a large application looks like this:

     :- use_module(compatibility).   % load XYZ prolog compatibility
     :- use_module(                  % load generic parts
             [ error                 % errors and warnings
             , goodies               % general goodies (library extensions)
             , debug                 % application specific debugging
             , virtual_machine       % virtual machine of application
             , ...                   % more generic stuff
             ]).
     :- ensure_loaded(
             [ ...                   % the application itself
             ]).

The ‘use module’ declarations will import the public predicates from the generic modules into the user module. The ‘ensure loaded’ directive loads the modules that constitute the actual application. It is assumed these modules import predicates from each other using use module/[1,2] as far as necessary.

In combination with the object-oriented schema described below it is possible to define a neat modular architecture. The generic code defines general utilities and the message passing predicates (invoke/3 in the example below). The application modules define classes that communicate using the message passing predicates.

4.5.1 Object Oriented Programming

Another typical way to use the module system is for defining classes within an object oriented paradigm. The class structure and the methods of a class can be defined in a module and the explicit module-boundary overruling describes in section 4.6.2 can by used by the message passing code to invoke the behaviour. An outline of this mechanism is given below.

     %       Define class point
     :- module(point, []).           % class point, no exports
     %        name           type,           default access
     %                                       value
     variable(x,             integer,        0,      both).
     variable(y,             integer,        0,      both).
     %         method name   predicate name  arguments
     behaviour(mirror,       mirror,         []).
     mirror(P) :-
             fetch(P, x, X),
             fetch(P, y, Y),
             store(P, y, X),
             store(P, x, Y).

The predicates fetch/3 and store/3 are predicates that change instance variables of instances. The figure below indicates how message passing can easily be implemented:

     %       invoke(+Instance, +Selector, ?ArgumentList)
     %       send a message to an instance
     invoke(I, S, Args) :-
             class_of_instance(I, Class),
             Class:behaviour(S, P, ArgCheck), !,
             convert_arguments(ArgCheck, Args, ConvArgs),
             Goal =.. [P|ConvArgs],
             Class:Goal.

The construct ‘Module:Goal’ explicitely calls Goal in module Module. It is discussed in more detail in section 3.7.

4.6 Meta-Predicates in Modules

As indicated in the introduction, the problem with a predicate based module system lies in the difficulty to find the correct predicate from a Prolog term. The predicate ‘solution(Solution)’ can exist in more than one module, but ‘assert(solution(4))’ in some module is supposed to refer to the correct version of solution/1.

Various approaches are possible to solve this problem. One is to add an extra argument to all predicates (e.g. ‘assert(Module, Term)’). Another is to tag the term somehow to indicate which module is desired (e.g. ‘assert(Module:Term)’). Both approaches are not very attractive as they make the user responsible for chosing the correct module, inviting unclear programming by asserting in other modules. The predicate assert/1 is supposed to assert in the module it is called from and should do so without being told explicitely. For this reason, the notion context module has been introduced.

4.6.1 Definition and Context Module

Each predicate of the program is assigned a module, called it’s definition module. The definition module of a predicate is always the module in which the predicate was originally defined. Each active goal in the Prolog system has a context module assigned to it.

The context module is used to find predicates from a Prolog term. By default, this module is the definition module of the predicate running the goal. For meta-predicates however, this is the context module of the goal that invoked them. We call this module transparent in SWI-Prolog. In the ‘using maplist’ example above, the predicate maplist/3 is declared module transparent. This implies the context module remains extend, the context module of add extension/3. This way maplist/3 can decide to call extend atom in module extend rather than in it’s own definition module.

All built-in predicates that refer to predicates via a Prolog term are declared module transparent. Below is the code defining maplist.

     :- module(maplist, maplist/3).
     :- module_transparent maplist/3.
     %       maplist(+Goal, +List1, ?List2)
     %       True if Goal can succesfully be applied to all succesive pairs
     %       of elements of List1 and List2.
     maplist(_, [], []).
     maplist(Goal, [Elem1|Tail1], [Elem2|Tail2]) :-
             apply(Goal, [Elem1, Elem2]),
             maplist(Goal, Tail1, Tail2).

4.6.2 Overruling Module Boundaries

The mechanism above is sufficient to create an acceptable module system. There are however cases in which we would like to be able to overrule this schema and explicitely call a predicate in some module or assert explicitly in some module. The first is useful to invoke goals in some module from the user’s toplevel or to implement a object-oriented system (see above). The latter is useful to create and modify dynamic modules (see section 4.7).

For this purpose, the reserved term :/2 has been introduced. All built-in predicates that transform a term into a predicate reference will check whether this term is of the form ‘<Module>:<Term>’. If so, the predicate is searched for in Module instead of the goal’s context module. The :/2 operator may be nested, in which case the inner-most module is used.

The special calling construct <Module>:<Goal> pretends Goal is called from Module instead of the context module. Examples:

     ?- assert(world:done).  % asserts done/0 into module world
     ?- world:assert(done).  % the same

     ?- world:done.          % calls done/0 in module world

4.7 Dynamic Modules

Sofar, we discussed modules that were created by loading a module-file. These modules have been introduced on facilitate the development of large applications. The modules are fully defined at load-time of the application and normally will not change during execution. Having the notion of a set of predicates as a self-contained world can be attractive for other purposes as well. For example, assume an application that can reason about multiple worlds. It is attractive to store the data of a particular world in a module, so we extract information from a world simply by invoking goals in this world.

Dynamic modules can easily be created. Any built-in predicate that tries to locate a predicate in a specific module will create this module as a side-effect if it did not yet exist. Example:

     ?- assert(world_a, consistent),
        world_a:unknown(_, fail).

These calls create a module called ‘world a’ and make the call ‘world a:consistent’ succeed. Undefined predicates will not start the tracer or autoloader for this module (see unknown/2).

Import and export from dynamically created world is arranged via the predicates import/1 and

export/1:
     ?- world_b:export(solve(_,_)).          % exports solve/2 from world_b
     ?- world_c:import(world_b:solve(_,_)).  % and import it to world_c

4.8 Module Handling Predicates

This section gives the predicate definitions for the remaining built-in predicates that handle modules.

:- module(+Module, +PublicList)

This directive can only be used as the first term of a source file. It declares the file to be a module file, defining Module and exporting the predicates of PublicList. PublicList is a list of name/arity pairs.

module transparent +Preds Preds is a comma separated list of name/arity pairs (like dynamic/1). Each goal associated with a transparent declared predicate will inherit the context module from its parent goal.

context module(-Module)

Unify Module with the context module of the current goal. context module/1 itself is transparent.

export(+Head)

Add a predicate to the public list of the context module. This implies the predicate will be imported into another module if this module is imported with use module/[1,2]. Note that predicates are normally exported using the directive module/2. export/1 is meant to handle export from dynamically created modules. export list(+Module, ?Exports)

Unifies Exports with a list of terms. Each term has the name and arity of a public predicate of Module. The order of the terms in Exports is not defined. See also predicate property/2.

4.9 Compatibility of the Module System

The principles behind the module system of SWI-Prolog differ in a number of aspects from the Quintus Prolog module system.

• The SWI-Prolog module system allows the user to redefine system predicates.

• All predicates that are available in the system and user modules are visible in all other modules as well.

• Quintus has the ‘meta predicate/1’ declaration were SWI-Prolog has the module transparent/1 declaration.

The meta predicate/1 declaration causes the compiler to tag arguments that pass module sensitive information with the module using the :/2 operator. This approach has some disadvantages:

• Changing a meta predicate declaration implies all predicates calling the predicate need to be reloaded. This can cause serious consistency problems.

• It does not help for dynamically defined predicates calling module sensitive predicates.

• It slows down the compiler (at least in the SWI-Prolog architecture).

• At least within the SWI-Prolog architecture the run-time overhead is larger than the overhead introduced by the transparent mechanism.

Unfortunately the transparent predicate approach also has some disadvantages. If a predicate A passes module sensitive information to a predicate B, passing the same information to a module sensitive system predicate both A and B should be declared transparent. Using the Quintus approach only A needs to be treated special (i.e. declared with meta predicate/1)^{1}. A second problem arises if the body of a transparent predicate uses module sensitive predicates for which it wants to refer to its own module. Suppose we want to define findall/3 using assert/1 and retract/1^{2}. The example in figure 4.1 gives the solution.

The Quintus meta predicate/1 directive can in many cases be replaced by the transparent declaration. Figure 4.2 gives a definition of meta predicate/1 as available from the ‘quintus’ library package.

The discussion above about the problems with the transparent mechanism

1Although this would make it impossible to call B directly.

2The system version uses recordz/2 and recorded/3.

:- module(findall, [findall/3]).
:- dynamic
solution/1.
:- module_transparent
findall/3,
store/2.
findall(Var, Goal, Bag) :-
assert(findall:solution('$mark')),
store(Var, Goal),
collect(Bag).
store(Var, Goal) :-
Goal,                   % refers to context module of
                        % caller of findall/3
assert(findall:solution(Var)),
fail.
store(_, _).
collect(Bag) :-
...,

Figure 4.1: findall using modules

:- op(1150, fx, (meta_predicate)).
meta_predicate((Head, More)) :- !,
meta_predicate1(Head),
meta_predicate(More).
meta_predicate(Head) :-
meta_predicate1(Head).
meta_predicate1(Head) :-
Head =.. [Name|Arguments],
member(Arg, Arguments),
module_expansion_argument(Arg), !,
functor(Head, Name, Arity),
module_transparent(Name/Arity).
meta_predicate1(_).             % just a mode declaration
module_expansion_argument(:).
module_expansion_argument(N) :- integer(N).

Figure 4.2: Definition of meta predicate/1 CHAPTER 4. USING MODULES 2.1

– 84 –

Foreign Language Interface

SWI-Prolog offers a powerful interface to C [Kernighan & Ritchie, 1978]. The main design objectives of the foreign language interface are flexibility and performance. Most Prolog foreign language interfaces allow the user only to pass primitive data through the interface. The user should normally specify for each argument whether it is an input or output argument as well as the type of the argument. Because type checking and conversion to/from C data types is done by Prolog the actual foreign code is usually short if something simple is wanted. The SWI-Prolog interface does not offer these primitives. Instead Prolog terms in their internal representation are passed via the interface. This allows the user to write ‘logical’ predicates and pass arbitrary Prolog data over the interface. As a trade-off the user is responsible for type checking and should be careful not to violate consistency rules as Prolog provides access to its internal data structures.

5.1 Overview of the Interface

A special include file called “SWI-Prolog.h” should be included with each C-source file that is to be loaded via the foreign interface. The installation process installs this file in the directory include in the SWI-Prolog home directory (?- feature(home, Home).). This C-header file defines various data types, macros and functions that can be used to communicate with SWI-Prolog. Functions and macros can be divided into the following categories:

• Analysing arbitrary Prolog terms

• Constructing new terms or instantiating existing ones

• Returning control information to Prolog

• Registering foreign predicates with Prolog

• Registering variables with the garbage collector

• Calling Prolog from C

• Communicating about modules

• Printing standard Prolog warning/error messages

• Global actions on Prolog (halt, break, abort, etc.)

• Querying the status of Prolog

CHAPTER 5. FOREIGN LANGUAGE INTERFACE 2.1

5.2 Linking Foreign Modules

Foreign modules may be linked to Prolog in three ways. Using static linking, the extensions, a small description file and the basic SWI-Prolog object file are linked together to form a new executable. Using dynamic linking of object files, the extensions are linked into the running Prolog process. Finally, on some operating systems SWI-Prolog allows for loading dynamic libraries (called shared libraries (.so files) on Unix systems and Dynamic Link Libraries (.dll files) on many PC based operating systems.

5.2.1 What linking is provided?

The static linking schema can be used on all versions of SWI-Prolog. The feature/2 predicate may be used to find out what other linking methods are provided for this version.

• feature(load foreign, true)

If this succeeds the system provides the load foreign/2 and load foreign/5 predicates that allow for loading object files (.o files on Unix machines).

• feature(open shared object, true) If this succeeds the system provides the open shared object/2 and related predicates that allow for handling Unix shared object files based on the Unix library functions dlopen() and friends. See section 5.4.

Note that, as this feature conflicts with save/[1,2] and save program/[1,2], it is not enabled by default. To enable it, the system should be configured using:

         % sh configure --enable-dlopen

• feature(dll, true)

If this succeeds the system provides an interface for loading .DLL files by means of open dll/2 and friends. See section 5.4.

If either the feature open shared object or dll is true, the library library(shlib.pl) provides a common interface for loading foreign files from Prolog.

Note that a specific version of SWI-Prolog may offer multiple of these loading facilities.

5.2.2 What kind of loading should I be using?

All described approaches have their advantages and disadvantages. Static linking is portable and allows for debugging on all platforms. It is relatively cumbersome and the libraries you need to pass to the linker may vary from system to system.

Direct loading of object files is not very portable and generally works only on operating systems using the old BSD Unix a.out format for object and executable files. Also, the text of the loaded executable is in the data-segment of Prolog, disabling text-sharing and protection provided by Unix and some modern PC based operating systems.

Loading shared objects or DLL files provides sharing and protection and is generally the best choice. The problem is that save/[1,2] and save program/[1,2] donot cooperate with this mechanism.

Summarising, if you donot need save/[1,2] or save program/[1,2], loading based on library(shlib)

is probably the best choice. See section 5.4. Otherwise use loading object files directly for small things and static linking for large applications to exploit sharing and protection.

Development in SWI-Prolog and operating systems are likely to make shlib the standard foreign loading schema for SWI-Prolog.

Note that the definition of the foreign predicates is the same, regardless of the linking type used.

5.2.3 Static Linking

Below is an outline of the files structure required for statically linking SWI-Prolog with foreign extensions. .../pl refers to the SWI-Prolog home directory (see feature/2). <arch> refers to the architecture identifier that may be obtained using feature/2.

             .../pl/runtime/<arch>/pl.o Main object-file
             .../pl/include/SWI-Prolog.h Include file
             .../pl/include/SWI-Stream.h Stream I/O include file

.../pl/include/SWI-Exports Export declarations (AIX only)

             .../pl/include/stub.c  Extension stub

The definition of the foreign predicates is the same as for dynamic linking. Unlike with dynamic linking however, there is no initialisation function. Instead, the file .../pl/include/stub.c may be copied to your project and modified to define the foreign extensions. Below is stub.c, modified to link the lowercase example described later in this chapter:

/*  Copyright (c) 1991 Jan Wielemaker. All rights reserved.
    jan@swi.psy.uva.nl
    Purpose: Skeleton for extensions
*/
#include <stdio.h>
#include <SWI-Prolog.h>
extern foreign_t pl_lowercase(term, term);
PL_extension PL_extensions [] =
{
/*{ "name",      arity,  function,      PL_FA_<flags> },*/
  { "lowercase", 2       pl_lowercase,  0 },
  { NULL,        0,      NULL,          0 }     /* terminating line */
};

int
main(int argc, char **argv, char **env)
{ if ( !PL_initialise(argc, argv, env) )
    PL_halt(1);
  PL_halt(PL_toplevel() ? 0 : 1);
}

Now, a new executable may be created using the make(1) Makefile fragment below. The correct versions for the variables may be obtained using the feature/2 predicate:

?- feature(c_cc,         CC).
?- feature(c_ldflags,    LDFLAGS).
?- feature(c_staticlibs, STATICLIBS).
?- feature(c_libs,       LIBS).
?- feature(arch,         ARCH).
?- feature(home,         HOME).

     CC=gcc
     HOME=/usr/local/lib/pl-2.0.6
     CFLAGS=-I$(HOME)/include
     LDFLAGS=
     STATICLIBS=/usr/lib/libc.a
     LIBS=-lreadline -ltermcap -lm
     ARCH=i486-linux
     PLOBJ=$(HOME)/$(ARCH)/pl.o
     OBJ=lowercase.o stub.o
     lwpl:   $(PLOBJ) $(OBJ)
             $(CC) -o $@ $(LDFLAGS) $(PLOBJ) $(OBJ) $(STATICLIBS) $(LIBS)

The resulting lwpl file will load the standard prolog bootstrap file. Normally, your extensions will partly be written in Prolog. In this case you may wish to create a new bootfile that includes the standard Prolog system and your extensions. Write a toplevel loadfile that loads your application and add the following to your Makefile:

     PLFILES:        load.pl foo.pl bar.pl
     lwpl.qlf:       lwpl $(PLFILES)
                     ./lwpl -g mytoplevel \
                            -b $(HOME)/boot/init.pl \
                            -c load.pl

See also section 2.7 for compiling Prolog sources using the -c option.

5.2.4 Dynamic Linking based on load foreign/[2,5]

Portability Note

The incremental linker is highly system dependent. It can easily be ported to machines for which the C linker allows you to link an object file using the symbol table of a (running) executable and use BSD Unix format a.out files. On many Unix systems such an object file can be created using the -A option of ld(1). Some operating systems offer primitives for dynamic loading (AIX, MACH). The following call may be used to find out whether load foreign is functional:

     ?- feature(load_foreign, OK).

load foreign(+File, +Entry)

Load a foreign file or list of files specified by File. The files are searched for similar to consult/1. Except that the ‘.o’ extension is used rather than ‘.pl’. Thus ‘test’ is a valid specification for ‘test.o’ in the current directory, ‘[test, library(basics)]’ specifies ‘test.o’ in the current directory and ‘basics.o’ in one of the library directories.

Entry defines the entry point of the resulting executable. The entry point will be called by Prolog to install the foreign predicates. load foreign(+File, +Entry, +Options, +Libraries, +Size)

The first two arguments are identical to those of load foreign/2. Options is (a list of) additional option to be given to the loader. The default command is:^{1}

    $(CC) -N -A <symbolfile> -T <offset> -e <entry> -o <executable>
       <files> -lc

The options are inserted just before the files. Libraries is (a list of) libraries to be passed to the loader. They are inserted just after the files.

If Size is specified Prolog first assumes that the resulting executable will fit in Size bytes and do the loading in one pass. If the executable turns out to be larger than Size bytes the loading sequence is started again, using the calculated size. To determine the size of an executable specify a size that is too small. Prolog will then print the actual size on the current output stream.

foreign file(?File)

Is true if File is the absolute path name of a file loaded as foreign file.

5.3 Dynamic Linking of shared libraries

The interface defined in this section allows the user to load shared libraries (.so files on most Unix systems). This interface is portable to all machines providing the function dlopen(), normally from the library -ldl. To enable it, SWI-Prolog must be configured using

% sh configure --enable-dlopen

These functions provide the basic interface layer. It is adviced to use the predicates from section 5.4 in your application.

open shared object(+File, -Handle)

File is the name of a .so file (see your C programmers documentation on how to create a .so file). This file is attached to the current process and Handle is unified with a handle to the shared object.

close shared object(+Handle)

Detach the shared object identified by Handle.

call shared object function(+Handle, +Function)

Call the named function in the loaded shared library. The function is called without arguments and the return-value is ignored. Normally this function installs foreign language predicates using calls to PL register foreign().

5.4 Using the library shlib for .DLL and .so files

This section discusses the functionality of the (autoload) library shlib.pl, providing an interface to shared libraries. Currently it supports MS-Windows DLL (.dll) libraries and Unix .so (shared object) files. load foreign library(+Lib)

1details depend on your operating system.

Equivalent to load foreign library(Lib, install).

load foreign library(+Lib, +Entry)

Search for the given foreign library and link it to the current SWI-Prolog instance. The library may be specified with or without the extension. It is searched for using the operating-system defined searching mechanism. If the library can be loaded, the function called Entry will be called without arguments. The return value of the function is ignored.

The Entry function will normally call PL register foreign() to declare functions in the library as foreign predicates.

unload foreign library(+Lib)

If the foreign library defines the function uninstall, this function will be called without arguments and its return value is ignored. Next, abolish/2 is used to remove all known foreign predicates defined in the library. Finally the library itself is detatched from the process.

current foreign library(-Lib, -Predicates)

Query the currently loaded foreign libraries and their predicates. Predicates is a list with elements of the form Module:Head, indicating the predicates installed with PL register foreign().

Figure 5.1 connects a Windows message-box using a foreign function. This example was tested using Windows-NT and Microsoft Visual C++ 2.0.

 #include <windows.h>
 #include <SWI-Prolog.h>
 static foreign_t
 pl_say_hello(term_t to)
 { if ( PL_is_atom(to) )
   { char *a = PL_atom_value(PL_atomic(to));
     MessageBox(NULL, a, "DLL test", MB_OK|MB_TASKMODAL);
     PL_succeed;
   }
   PL_fail;
 }
 install_t
 install()
 { PL_register_foreign("say_hello", 1, pl_say_hello, 0);
 }

Figure 5.1: MessageBox() example in Windows-NT

5.5 Interface Data types

The interface functions can be divided into two groups. The first group are functions to obtain data from Prolog or pass data to Prolog. These functions use Prolog internal data types. The second group consists of type conversion functions convert between Prolog internal data and C primitive types. Below is a description of the types used in the interface.

term t Terms represent arbitrary Prolog data (variables, atoms, integers, floats and compound terms). Terms live either until backtracking takes us back to a point before the term was created or the garbage collector has collected the term.

atomic t Atomics are Prologs primitive data types (integers, atoms and floats). They can be transformed to C data types (int, char * resp. double). The Prolog representation for an integer is a tagged version of that integer. The mapping between C ints and Prolog integers can only be different over different releases of SWI-Prolog. Atoms are represented by a pointer to a data structure on the Prolog heap. Each such data structure is a unique representation of a string (e.g. to verify that two atoms represent the same string comparing the atoms suffices). The mapping between atoms and string are likely to vary over different sessions of Prolog. Floats are represented as (tagged) pointers to a float living on the global stack. For their life time the same rules apply as for terms. Whether two floats represent the same number can only be discovered by transforming both to C floats and then comparing them. Strings are represented as a tagged pointer to a char * on the global stack or heap. The rules for their lifetime and comparison equal those for floats and terms.

functor t A functor is the internal representation of a name/arity pair. They are used to find the name and arity of a compound term as well as to construct new compound terms. Like atoms they live for the whole Prolog session and are unique.

predicate t Handle to a foreign predicate using with PL call predicate(). Predicates live forever (although they can loose their definition).

module t A module is a unique handle to a Prolog module. Modules are used only to call predicates in a specific module.

foreign t Return type for a C-function implementing a Prolog predicate.

install t Type for the install() and uninstall() functions of shared or dynamic link libraries. See section 5.4.

5.6 The Foreign Include File

5.6.1 Argument Passing and Control

If Prolog encounters a foreign predicate at run time it will call a function specified in the predicate definition of the foreign predicate. The arguments (1, ..., arity) pass the Prolog arguments to the goal as Prolog terms. Foreign functions should be declared of type foreign t. Deterministic foreign functions have two alternatives to return control back to Prolog:

void PL succeed Succeed deterministically. PL succeed is defined as “return TRUE”.

void PL fail Fail and start Prolog backtracking. PL fail is defined as “return FALSE”.

Non-deterministic Foreign Predicates

By default foreign predicates are deterministic. Using the PL FA NONDETERMINISTIC attribute (see PL register foreign()) it is possible to register a predicate as a non-deterministic predicate. Writing non-deterministic foreign predicates is slightly more complicated as the foreign function needs context information for generating the next solution. Note that the same foreign function should be prepared to be simultaneously active in more than one goal. Suppose the natural number below n/2 is a nondeterministic foreign predicate, backtracking over all natural numbers lower than the first argument. Now consider the following predicate:

     quotient_below_n(Q, N) :-
             natural_number_below_n(N, N1),
             natural_number_below_n(N, N2),
             Q =:= N1 / N2, !.

In this predicate the function natural number below n/2 simultaneously generates solutions for both its invocations.

Non-deterministic foreign functions should be prepared to handle three different calls from Prolog:

Initial call (PL FIRST CALL)

Prolog has just created a frame for the foreign function and asks it to produce the first answer.

Redo call (PL REDO)

The previous invocation of the foreign function associated with the current goal indicated it was possible to backtrack. The foreign function should produce the next solution.

Terminate call (PL CUTTED)

The choice point left by the foreign function has been destroyed by a cut. The foreign function is given the opportunity to clean the environment.

Both the context information and the type of call is provided by an argument of type foreign t appended to the argument list for deterministic foreign functions. The macro PL foreign control() extracts the type of call from the control argument. The foreign function can pass a context handle using the PL retry() macro and extract the handle from the extra argument using the PL foreign context() macro.

void PL retry(handle)

The foreign function succeeds while leaving a choice point. On backtracking over this goal the foreign function will be called again, but the control argument now indicates it is a ‘Redo’ call and the macro PL foreign context() will return the handle passed via PL retry(). This handle is a 30 bits signed value (two bits are used for status indication).

int PL foreign control(control argument) Extracts the type of call from the control argument. The return values are described above. Note that the function should be prepared to handle the PL CUTTED case and should be aware that the other arguments are not valid in this case.

long PL foreign context(control argument) Extracts the context from the context argument. In the call type is PL FIRST CALL the context value is 0L. Otherwise it is the value returned by the last PL retry() associated with this goal (both if the call type is PL REDO as PL CUTTED).

Note: If a non-deterministic foreign function returns using PL succeed or PL fail, Prolog assumes the foreign function has cleaned its environment. No call with control argument PL CUTTED will follow.

The code of figure 5.2 shows a skeleton for a non-deterministic foreign predicate definition.

     typedef struct                  /* define a context structure */
     { ...
     } context;
     foreign_t
     my_function(term_t a0, term_t a1, foreign_t handle)
     { struct context * ctxt;
       switch( PL_foreign_control(handle) )
       { case PL_FIRST_CALL:
             ctxt = (struct context *) malloc(sizeof(struct context));
             ...
             PL_retry(ctxt);
         case PL_REDO:
             ctxt = (struct context *) PL_foreign_context(handle);
             ...
             PL_retry(ctxt);
         case PL_CUTTED:
             free(ctxt);
             PL_succeed;
       }
     }

Figure 5.2: Skeleton for non-deterministic foreign functions

5.6.2 Analysing Terms via the Foreign Interface

Each argument of a foreign function (except for the control argument) is of type term t. To analyse a term one should first obtain the type of the term. Primitive terms can then be transformed into atomic data in internal Prolog representation. This atomic data can be transformed into Cdata types. Complex terms are analysed in terms on their functor and arguments. The arguments themselves are terms, allowing the same procedure to be repeated recursively.

int PL type(term t) Obtain the type of term, which should be a term returned by one of the other interface predicates or passed as an argument. The function returns the type of the Prolog term. The type identifiers are listed below.

 PL VARIABLE

An unbound variable. The value of term as such is a unique identifier for the variable.

PL ATOM  A Prolog atom.
PL STRING  A Prolog string.
PL INTEGER  A Prolog integer.
PL FLOAT  A Prolog floating point number.

 PL TERM

A compound term. Note that a list is a compound term with name ‘.’ and arity 2.

The functions PL is <type> allow form an alternative to PL type. The test “PL is var(term)” is equivalent to “PL type(term) == PL VARIABLE”, but the first is considerably faster.

int PL is var(term t) Returns non-zero if term is a variable.

int PL is atom(term t) Returns non-zero if term is an atom.

int PL is string(term t) Returns non-zero if term is a string.

int PL is int(term t) Returns non-zero if term is an integer.

int PL is float(term t) Returns non-zero if term is a float.

int PL is term(term t) Returns non-zero if term is a compound term.

atomic t PL atomic(term t) Return the atomic value of term in Prolog internal representation. Term should be atomic (e.g. atom, integer, float or string).

long PL integer value(atomic t) Transforms an integer from Prolog internal representation into a C long.

double PL float value(atomic t) Transforms a float from Prolog internal representation into a C double.

char * PL atom value(atomic t) Transforms an atom from Prolog internal representation into a 0-terminated C char *. The pointer points directly into the Prolog heap and can assumed to be static. The contents of the character string however should under NO circumstances be modified.

char * PL string value(string) Transform a string from Prolog internal representation into a C char *. The pointer points directly into the Prolog data area. Unlike the pointer returned by PL atom value() the C user should copy the value to a private data area if its value should survive the current foreign language call. Like PL atom value(), changing the contents of the character string is NOT allowed.

functor t PL functor(term t) term should be a complex term. The return value is a unique identifier of the term’s name and arity. The following example demonstrates this:

     pl_same_functor(term_t t1, term_t t2)
     { if ( !PL_is_term(t1) || !PL_is_term(t2) )
         PL_fail;
       if ( PL_functor(t1) == PL_functor(t2) )
         PL_succeed;
       PL_fail;
     }

atomic t PL functor name(functor t) Return an atom representing the name of functor. To get the functor name as char * of a term which is known to be compound:

#define functor name(term) PL atom value(PL functor name(PL functor(term)))

int PL functor arity(functor t) Return a C integer representing the arity of functor.

term PL arg(term t, int) Return the int-th argument of term. Argument counting starts at 1 and is valid up to and including the arity of term. No checks on these boundaries are performed.

Figure 5.3 shows a definition of display/1 to illustrate the described functions.

5.6.3 Instantiating and Constructing Terms

Terms are instantiated as in Prolog itself by unification. Variables can be unified with atomic data, with a functor and with other terms. New terms are first constructed as a single unbound variable.

term t PL new term() Create a new term. The term is an unbound variable living on the global stack. In the current implementation it lives until Prolog backtracks to before this call. Garbage collection might change this in the future.

atomic t PL new atom(char *)

Create a Prolog atom from a C char *. The contents of the char * are copied to the Prolog heap.

atomic t PL new string(char *) Create a Prolog string, living on the global stack. The contents of the char * are copied into Prolog’s data area.

atomic t PL new integer(long)

Create a Prolog integer from a C long. Note that the integer is truncated to 28 bits. No checks on this are performed.

atomic t PL new float(double)

Create a Prolog float living on the global stack from double.

functor t PL new functor(atomic t, int) Create a Prolog functor identifier form atomic (which should be an atom) and int, the arity. Arity is valid for any arity ≥ 0. Arity = 0 is used internally, but none of the interface functions use it.

pl_display(term_t t)
{ functor_t functor;
int arity, n;
switch( PL_type(t) )
{ case PL_VARIABLE:
printf("_%d", t);
break;
case PL_ATOM:
printf("%s", PL_atom_value(PL_atomic(t)));
break;
case PL_STRING:
printf("\"%s\"", PL_string_value(PL_atomic(t)));
break;
case PL_INTEGER:
printf("%d", PL_integer_value(PL_atomic(t)));
break;
case PL_FLOAT:
printf("%f", PL_float_value(PL_atomic(t)));
break;
case PL_TERM:
functor = PL_functor(t);
arity = PL_functor_arity(functor);
printf("%s", PL_atom_value(PL_functor_name(functor)));
printf("(");
pl_display(PL_arg(t, 1));
for( n = 2; n <= arity; n++)
{ printf(", ");
  pl_display(PL_arg(t, n));
}
printf(")");
break;
default:
PL_fatal_error("Illegal type in pl_display(): %d",
                                        PL_type(t));
}
PL_succeed;
}

Figure 5.3: A Foreign definition of display/1 int PL unify(term t, term t)

Unify two terms. Return value is TRUE or FALSE.

int PL unify atomic(term t, atomic t) Unify a term with an atomic value.

int PL unify functor(term t, functor t) Unify a term with a functor. The unification simply succeeds if term is already instantiated to a term with functor functor. If term is variable it will be instantiated to the most general term of functor (e.g. a term with all arguments unbound variables). Otherwise FALSE is returned.

If this call succeeds the arguments can be further instantiated by calling PL arg() and recursively unifying the returned terms.

An example of using these functions is shown in figure 5.4.

5.6.4 Interaction with the garbage collector and stack-shifter

C-functions that manipulate Prolog terms manipulate pointers to the Prolog runtime stacks. Prolog implements two mechanisms for avoiding stack overflow: garbage collection and stack expansion. On machines that allow for it, Prolog will use virtual memory management to detect stack overflow and expand the runtime stacks. On other machines Prolog will reallocate the stacks and update all pointers to them. To do so, Prolog needs to know which variables of active C-functions contain references to Prolog data.

C-variables may be registered with the Prolog engine using the macro PL lock() and unregistered using PL unlock(). These macros should be perfectly balanced and any term locked in a C-function needs to be unlocked before control is passed back to Prolog.

A C-variable that is registered must hold valid Prolog data or ‘0’.

void PL lock(term t) Register the named C-variable with the Prolog engine. The variable should hold a valid Prolog term. The value of the variable may be changed while it remains locked. Each locked variable must be unlocked using PL unlock(). Locking and unlocking must be balanced.

void PL unlock(term t) Unlock a locked variable. If the named variable is not the most recently locked variable an error message is printed. If a foreign function leaves variables unlocked an error message is issued as well.

When is locking necessary

Stacks shifts or garbage collections may be forced if there is insufficient space on the stacks. Data is pushed on the stacks by most of the term construction functions and if the Prolog engine is called using PL call() or PL call predicate().

By default the Prolog engine ensures the stacks have a minimum of ‘min free’ (see stack parameter/4) space when a foreign predicate is activated. If this is insufficient, Prolog checks whether a garbage collection may be performed or the stacks may be enlarged.^{2} By default Prolog assumes it is not save to shift the stacks or perform a garbage collection when foreign code is active.

2When using virtual memory based stacks the system can always enlarge the stacks as it needs not to shift them.

Simple C-defined predicates that do not call Prolog and do not use the term-construction functions intensively do not need to use PL lock() and PL unlock(). C-defined predicates that perform call-back on Prolog or use the term construction primitives to (potentially) create large data structures should protect their variables and should defined the PL FA GCSAVE attribute (see PL register foreign()).

5.6.5 Calling Prolog from C

The Prolog system can be called back from C. This is done by constructing a term with the functions described above and then calling PL call(). PL call() executes the goal and returns TRUE or FALSE depending on success or failure of the called predicate. There are no means to backtrack over the Prolog predicate. If alternatives are wanted call findall/3 and read the result from the third argument.

int PL call(term t, module t) Call term just like the Prolog predicate once/1. Term is called in the specified module, or in the context module if module t = NULL. Returns TRUE if the call succeeds, FALSE otherwise. Figure 5.4 shows an example to obtain the number of defined atoms. All checks are omitted to improve readability.

5.6.6 Discarding Data

The Prolog data created during setting up the call and calling Prolog can in most cases be discarded right after the call. See figure 5.4 for an example.

void PL mark(bktrk buf) Mark the global and trail stacks in bktrk buf.

void PL bktrk(bktrk buf) Undo all changes in the runtime stacks since a snapshot has been made in buffer using PL mark(). Changes to the heap are not affected.

It is not necessary to call PL bktrk() for each PL mark(). The user should ensure that PL bktrk() is never called with a buffer that is created after a buffer to which PL bktrk() has been called. Thus PL mark(b1) ... PL mark(b2) ... PL bktrk(b1) is valid, but it is not allowed to call PL bktrk(b2) after this sequence.

5.6.7 Calls based on predicate references

In some situations, callback is highly time-critical and needs to be performed often on the same predicate. In these cases, Pl call() may be too slow as it involves building the gaol using various unification calls and calling PL call() that will again unpack the call-term. In these cases the interface described in this section may be useful.

predicate t PL predicate(functor t, module t) Return a handle to the given predicate in the given module. If module t is NULL, the current context module will be used. This call always succeeds, possibly creating a handle to an undefined predicate.

 int
 count_atoms()
 { term t;
   int atoms;
   bktrk_buf buf;
   PL_mark(&buf);            /* mark the global stack */
   t = PL_new_term();        /* create `statistics(atoms, Var)' */
   PL_unify_functor(t, PL_new_functor(PL_new_atom("statistics"), 2));
   PL_unify_atomic(PL_arg(t,1), PL_new_atom("atoms"));
   PL_call(t, NULL);         /* call it in current module */
                             /* extract the value from the 2nd arg */
   atoms = PL_integer_value(PL_atomic(PL_arg(t, 2)));
   PL_bktrk(&buf);           /* discard global stack data created */
   return atoms;
 }

Figure 5.4: Calling Prolog

int PL call predicate(module t, int debug, predicate t, term t *argv) Use a predicate handle to call predicate with the given arguments. The vector argv must point to a vector of Prolog terms with enough elements for the predicate. The module argument defines the context module of the goal if the called predicate is module transparent. If this argument is specified is NULL, this is the current context module. If no context is available it is the user module. If the debug argument is FALSE, the call will be hidden from the Prolog debugger. The module and debug arguments are in almost all normal cases NULL and TRUE. They are needed for some internal cases. PL call predicate() is the function containing the actual Prolog Virtual Machine Interpreter, flattening the call-stack as far as possible^{3}

The following example realises the same as the example from figure 5.4

Finally, the direct predicate interface provides some utility functions.

int PL predicate arity(predicate t)

Returns the number of arguments required by the predicate. The argument vector provided to PL call predicate() should contain at least this number of elements.

atomic t PL predicate name(predicate t) Returns an atom identifying the name of the predicate.

functor t PL predicate functor(predicate t) Functor description of the term. This is always the same as the first argument of the PL predicate() call used to find the predicate.

3Especially on the SUN SPARC cpu this is critical for good Prolog/C/Prolog calling performance

 int
 count_atoms()
 { term_t t[2];
   int atoms;
   bktrk_buf buf;
   PL_mark(&buf);            /* mark the global stack */
   t[0] = PL_new_term();        /* create `statistics(atoms, Var)' */
   t[1] = PL_new_term();
   PL_unify_atomic(t[0], PL_new_atom("atoms"));
   PL_call_predicate(NULL, TRUE,
                     PL_predicate(PL_functor(PL_new_atom("statistics"), 2)
                                  PL_new_module(PL_new_atom("user"))),
                     t);
                             /* extract the value from the 2nd arg */
   atoms = PL_integer_value(PL_atomic(t[1]));
   PL_bktrk(&buf);           /* discard global stack data created */
   return atoms;
 }

Figure 5.5: Using PL call predicate

module t PL predicate module(predicate t) Returns a handle to the module in which the predicate is defined. Note that this is not necessarily the same as the module handle used to locate the predicate with PL predicate() as the predicate may be imported. As predicate modifications may change the import/export relations, the return value may change between calls.

5.6.8 Foreign Code and Modules

Modules are identified via a unique handle. The following functions are available to query and manipulate modules.

module t PL context()

Return the module identifier of the context module of the currently active foreign predicate.

term t PL strip module(term t, module t *) Utility function. If term t is a term, possibly holding the module construct module:rest this function will return rest and fill module * with module. For further nested module constructs the inner most module is returned via module *. If term is not a module construct term will simply be returned. If module * is NULL it will be set to the context module. Otherwise it will be left untouched. The following example shows how to obtain the plain term and module if the default module is the user module:

     { module m = PL_new_module(PL_new_atom("user"));
       if ( (term = PL_strip_module(term, &m)) == NULL )
         return PL_warning("Illegal module specification");
       ...

atomic t PL module name(module t) Return the name of module as an atom.

module t PL new module(atomic t) Find an existing or create a new module with name specified by the atom atomic.

5.6.9 Catching Signals (Software Interrupts)

SWI-Prolog catches the Unix signals SIGINT, SIGFPE and SIGSEGV. To avoid problems with foreign code attempting to catch these signals foreign code should call PL signal() to install signal handlers rather than the Unix library function signal(). SWI-Prolog will always handle SIGINT itself. SIGFPE and SIGSEGV are passed to the foreign code handlers if Prolog did not expect that signal.

void (*PL signal(sig, func))() This function should be used to install signal handlers rather than the Unix library function signal(). It ensures consistent signal handling between SWI-Prolog and the foreign code and reinstalls signal handlers if a state created with save program/1 is restarted.

5.6.10 Errors and warnings

Two standard functions are available to print standard Prolog errors to the standard error stream.

int PL warning(format, a1, ...) Print an error message starting with ‘[WARNING: ’, followed by the output from format, followed by a ‘]’ and a newline. Then start the tracer. format and the arguments are the same as for printf(2). Always returns FALSE.

void PL fatal error(format, a1, ...) Print a message like PL warning(), but starting with ‘FATAL ERROR: ’ and then exits Prolog.

5.6.11 Environment Control from Foreign Code

int PL action(int, C type)

Perform some action on the Prolog system. int describes the action, C type provides the argument if necessary. The actions are listed in table 5.1.

5.6.12 Querying Prolog

C type PL query(int) Obtain status information on the Prolog system. The actual argument type depends on the PL ACTION TRACE Start Prolog tracer PL ACTION DEBUG Switch on Prolog debug mode PL ACTION BACKTRACE Print backtrace on current output stream. The argument

(an int) is the number of frames printed.

PL ACTION HALT Halt Prolog execution. This action should be called rather than Unix exit() to give Prolog the opportunity to clean up. This call does not return.

PL ACTION ABORT Generate a Prolog abort. This call does not return. PL ACTION BREAK Create a standard Prolog break environment. Returns af-

ter the user types control-D.

PL ACTION SYMBOLFILE The argument (a char *) is considered to be hold the symbolfile for further incremental loading. Should be called by user applications that perform incremental loading as well and want to inform Prolog of the new symbol table.

Table 5.1: PL action() options

information required. int describes what information is wanted. The options are given in table 5.2.

PL QUERY ARGC Return an integer holding the number of arguments given

to Prolog from Unix.

PL QUERY ARGV Return a char ** holding the argument vector given to

Prolog from Unix.

PL QUERY SYMBOLFILE Return a char * holding the current symbol file of the run-

ning process.

PL QUERY ORGSYMBOLFILE Return the initial symbol file (before loading) of Prolog. By setting the symbol file to this value no name clashes can occur with previously loaded foreign files (but no symbols can be shared with earlier loaded modules as well).

Table 5.2: PL query() options

5.6.13 Registering Foreign Predicates

int PL register foreign(name, arity, function, flags) Register a C-function to implement a Prolog predicate. After this call returns successfully a predicate with name name (a char *) and arity arity (a C int) is created. When called in Prolog, Prolog will call function. flags forms bitwise or’ed list of options for the installation. These are:

PL FA NOTRACE Predicate cannot be seen in the tracer PL FA TRANSPARENT Predicate is module transparent PL FA NONDETERMINISTIC Predicate is non-deterministic. This attribute is currently

ignored, but will probably be used in future versions.

PL FA GCSAVE The C-implementation properly uses PL lock() and PL unlock() to protect variables from the garbage collector and stack-shifter

5.6.14 Foreign Code Hooks

For various specific applications some hooks re provided.

PL dispatch hook t PL dispatch hook(PL dispatch hook t) If this hook is not NULL, this function is called when reading from the terminal. It is supposed to dispatch events when SWI-Prolog is connected to a window environment. It can return two values: PL DISPATCH INPUT indicates Prolog input is available on file descriptor 0 or PL DISPATCH TIMEOUT to indicate a timeout. The old hook is returned. The type

PL dispatch hook t is defined as:
    typedef int  (*PL_dispatch_hook_t)(void);

void PL abort hook(PL abort hook t) Install a hook when abort/0 is executed. SWI-Prolog abort/0 is implemented using C setjmp()/longjmp() construct. The hooks are executed in the reverse order of their registration after the longjmp() took place and before the Prolog toplevel is reinvoked. The type

PL abort hook t is defined as:
    typedef void (*PL_abort_hook_t)(void);

int PL abort unhook(PL abort hook t) Remove a hook installed with PL abort hook(). Returns FALSE if no such hook is found, TRUE otherwise.

void PL reinit hook(PL reinit hook t) Install a hook that is called when a saved program (using save program/[1,2]) is restored. The hooks are called in reverse order. The type PL reinit hook t is defined as:

    typedef void (*PL_reinit_hook_t)(int argc, char **argv);

int PL reinit unhook(PL reinit hook t) Remove a hook installed with PL reinit hook(). Returns FALSE if no such hook is found, TRUE otherwise.

5.6.15 Embedding SWI-Prolog in a C-program

As of version 2.1.0, SWI-Prolog may be embedded in a C-program. To reach at a compiled Cprogram with SWI-Prolog as an embedded application is very similar to creating a statically linked SWI-Prolog executable as described in section 5.2.3.

The file pl-stub.c defines SWI-Prologs default main program:

 int
 main(int argc, char **argv, char **env)
 { if ( !PL_initialise(argc, argv, env) )
     PL_halt(1);
   PL_halt(PL_toplevel() ? 0 : 1);
 }

This may be replaced with your own main C-program. The interface function PL initialise() must be called before any of the other SWI-Prolog foreign language functions described in this chapter. PL initialise() interprets all the command-line arguments, except for the -t toplevel flag that is interpreted by PL toplevel().

int PL initialise(int argc, char **argv, char **environ) Initialises the SWI-Prolog heap and stacks, restores the boot QLF file, loads the system and personal initialisation initialisation files, runs the at initialisation/1 hooks and finally runs the -g goal hook.

PL initialise() returns 1 if all initialisation succeeded and 0 otherwise. Various fatal errors may cause PL initialise to call PL halt(1), preventing it from returning at all.

int PL toplevel()

Runs the goal of the -t toplevel switch (default prolog/0) and returns 1 if successfull, 0 otherwise.

void PL halt(int status) Cleanup the Prolog environment and calls exit() with the status argument.

5.7 Example of Using the Foreign Interface

Below is an example showing all stages of the declaration of a foreign predicate that transforms atoms possibly holding uppercase letters into an atom only holding lower case letters. Figure 5.6 shows the C-source file.

5.7.1 C-Source file (lowercase.c)

/*  Include file depends on local installation */
#include <SWI-prolog.h>
#include <ctype.h>
foreign_t
pl_lowercase(term_t u, term_t l)
{ char *copy;
  char *s, *q;
  atomic_t la;
  if ( !PL_is_atom(u) )
    return PL_warning("lowercase/2: instantiation fault");
  s = PL_atom_value(PL_atomic(u));
  copy = (char *) malloc(strlen(s)+1);
  for( q=copy; *s; q++, s++)
    *q = (isupper(*s) ? tolower(*s) : *s);
  *q = '\0';
  la = PL_new_atom(copy);
  free(copy);
  return PL_unify_atomic(l, la);
}
install_t
init_lowercase()
{ PL_register_foreign("lowercase", 2, pl_lowercase, 0);
}

Figure 5.6: Lowercase source file

5.7.2 Compiling and Loading Foreign Code

     sun% cc -I/usr/local/lib/pl/include -O -c lowercase.c
     sun% pl
     Welcome to SWI-Prolog (version 2.1.3, July 1995)
     Copyright (c) 1990-1995, University of Amsterdam. All rights reserved.
     1 ?- load_foreign(lowercase, init_lowercase).
     foreign file(s) lowercase loaded, 0.016667 seconds, 464 bytes.
     Yes
     2 ?- lowercase('Hello World!', L).
     L = 'hello world!'
     Yes

5.8 Notes on Using Foreign Code

5.8.1 Garbage Collection and Foreign Code

Currently no interface between foreign code and the garbage collector has been defined. The garbage collector is disabled during execution of foreign code. Future versions might define such an interface. This probably will introduce incompatible changes to the current interface definition.

5.8.2 Memory Allocation

SWI-Prolog’s memory allocation is based on the malloc() library routines. Foreign applications can savely use malloc(), realloc() and free(). Memory allocation using brk() or sbrk() is not allowed as these calls conflict with malloc().

5.8.3 Debugging Foreign Code

NOTE: this section is highly machine dependent. The tricks described here are tested on SUN-3 and SUN-4. They might work on other BSD variants of Unix.

Debugging incrementally loaded executables is a bit more difficult than debugging normal executables. The oldest way of debugging (putting print statements in your code at critical points) of course still works. ‘Post-crash’ debugging however is not possible. For adb/dbx to work they need (besides the core) the text segment and the symbol table. The symbol table lives somewhere on /tmp (called ‘/tmp/pl ld ... .’, where ‘...’ is the process id and ‘.’ is an additional number to make sure the temporary file is unique. The text segment lives partly in the core (the incremental loaded bit) and partly in the SWI-Prolog executable.

The only way to debug foreign language code using a debugger is by starting the debugger on the running core image. Dbx(1) can do this. First compile the source files to be debugged with the ‘-g’ option to include dbx debugging information. Then load them into SWI-Prolog. Now obtain the name of the current symbol table and the process id of Prolog. Then start dbx (or dbxtool) using

     sun% dbx[tool] <symbol file> <pid>

Should this be done often then the following foreign predicate definition might help:

     pl_dbx()
     { char *symbolfile = PL_query(PL_QUERY_SYMBOLFILE);
       char cmd[256];
       sprintf(cmd, "dbxtool %s %d &", symbolfile, getpid());
       if ( system(cmd) == 0 )
         PL_succeed;
       else
         PL_fail;
     }

Register this predicate as dbx/0 using the following call in your initialisation function:

     PL_register_foreign("dbx", 0, pl_dbx, 0);

5.8.4 Name Conflicts in C modules

In the current version of the system all public C functions of SWI-Prolog are in the symbol table. This can lead to name clashes with foreign code. Someday I should write a program to strip all these symbols from the symbol table (why does Unix not have that?). For now I can only suggest to give your function another name. You can do this using the C preprocessor. If –for example– your foreign package uses a function warning(), which happens to exist in SWI-Prolog as well, the following macro should fix the problem.

     #define warning warning_

5.8.5 Compatibility of the Foreign Interface

As far as I am aware of, there is no standard for foreign language interfaces in Prolog. The SWI-Prolog interface is no attempt to propose such a standard. It is (in part) tailored to the possibilities of the SWI-Prolog machinery. BIM-Prolog has a similar interface to analyse and construct terms. The major difference is that they have garbage collection and calls are made available to lock and unlock terms for garbage collection. I built a similar interface to Edinburgh C-Prolog (although less clean). This at least tells us that the interface can work for various forms of the WAM as well as a structure sharing Prolog.

As no standard exists nor emerges, users of the foreign language interface should carefully design the interface if the C-code should be portable to other Prolog implementation. The best advice to give is to define a small interface layer around the C-application and interface this to Prolog.

Generating Runtime Applications

This chapter describes the features of SWI-Prolog for delivering applications that can run without the development version of the system installed.

A SWI-Prolog built application consists of at least two parts: the emulator and the compiled application. The latter is in the same format as a SWI-Prolog boot-file and SWI-Prolog pre-compiled (QLF) file. This format is fast loadable and abstracted just far enough to be machine independent. This implies an application delivered in binary format can run on any computer for which an emulator is available without modification.

qsave program(+File, +ListOfOptions)

Saves the current state of the program to the file ‘File’. The result is an executable shell-script, that will start the emulator. ListOfOptions is a list of Key = Value pairs. The available keys are described in table 6.1.

Key  Option Type Description
local  -L  K-bytes Size (Limit) of local stack
global  -G  K-bytes Size (Limit) of global stack
trail  -T  K-bytes Size (Limit) of trail stack
argument  -A  K-bytes Size (Limit) of argument stack
goal  -g  atom Initialisation goal
toplevel  -t  atom Prolog toplevel goal
init file  -f  atom Personal initialisation file
autoload  bool If true, run autoload/0 first
map  atom File containing info on dump

Table 6.1: Key = Value pairs for qsave program/2

The /bin/sh script contains the following data:

1. The shell script header starts as:

#!/bin/sh
#SAVE-VERSION=<num>
#PROLOG-VERSION=<num>
exec ${SWIPL-/path-to-emulator} -x $0 "$@"

CHAPTER 6. GENERATING RUNTIME APPLICATIONS 2.1

2. The settings section contains the default values for the various command line options.

3. The predicates section contains all predicates from the currently running system. Clauses of predicates defined as volatile (see volatile/1) are not saved. Neither are foreign predicates (see also below).

4. The record section contains the database records saved with recorda/3 and friends. The current version saves records using directives.

5. The flag section contains the global flags saved using the flag/3 predicate. Flags are saved as directives.

6. The feature section contains all features that do not originate from the emulator itself.

    See set feature/1.

7. The import section contains the imports as far as they are not handled by the autoimport system. That is, an import is stored if the module is user or the module user contains a different definition as the one imported in the target module.’

Before writing the data to file, qsave program/2 will run autoload/0 to all required autoloading the system can discover. See autoload/0.

Provided the application does not require any of the Prolog libraries to be loaded at runtime, the only file from the SWI-Prolog development environment required is the emulator itself. The emulator may be built in two flavours. The default is the development emulator. The runtime emulator is similar, but lacks the tracer. The stand-alone program chpl may be used to change the default path to the emulator.

qsave program(+File)

Equivalent to qsave program(File, []).

autoload Check the current Prolog program for predicates that are refered to, are undefined and have a definition in the Prolog library. Load the appropriate libraries.

This predicate is used by qsave program/[1,2] to ensure the saved state will not depend on one of the libraries. Autoload/0 will find all direct references to predicates. It does not find predicates referenced via meta-predicates. The predicate log/2 is defined in the library(quintus) to provide a quintus compatible means to compute the natural logarithm of a number. The following program will behave correctly if its state is executed in an environment where the library(quintus) is not available:

    logtable(From, To) :-
            From > To, !.
    logtable(From, To) :-
            log(From, Value),
            format('~d~t~8|~2f~n', [From, Value]),
            F is From + 1,
            logtable(F, To).

However, the following implementation refers to log/2 through the meta-predicate maplist/2. Autoload will not be able to find the reference. This problem may be fixed either by loading the module libtary(quintus) explicitely or use require/1 to tell the system that the predicate log/2 is required by this module.

    logtable(From, To) :-
            findall(X, between(From, To, X), Xlist),
            maplist(log, Xlist, SineList),
            write_table(Xlist, SineList).
    write_table([], []).
    write_table([I|IT], [V|VT]) :-
            format('~d~t~8|~2f~n', [I, V]),
            write_table(IT, VT).

volatile +Name/Arity, ...

Declare that the clauses of specified predicates should not be saved to the program. The volatile declaration is normally used to avoid that the clauses of dynamic predicates that represent data for the current session is saved in the state file.

6.1 Limitations of qsave program

There are three areas that require special attention when using qsave program/[1,2].

• If the program is an embedded Prolog application or uses the foreign language interface, care has to be taken to restore the appropriate foreign context. See section 6.2 for details.

• If the program uses directives (:- goal. lines) that perform other actions then setting predicate attributes (dynamic, volatile, etc.) or loading files (consult, etc.), the directive may need

to be prefixed with initialization/1.

• ‘Database references as returned by clause/3, recorded/3, etc. are not preserved and may thus not be part of the database when saved.

6.2 Runtimes and Foreign Code

Some applications may need to use the foreign language interface. Object code is by definition machine-dependent and thus cannot be part of the saved program file.

To complicate the matter even furtherm there are various ways of loading foreign code:

• Using the library(shlib) predicates This is the preferred way of dealing with foreign code. It loads quickly and ensures an acceptable level of indepedence between the versions of the emulator and the foreign code loaded. It works on Unix machines supporting shared libraries and library functions to load them. Most modern Unixes satisfy this constraint.^{1}. It also works on the Win32 platform: Windows-NT, ’95 and Windows 3.1 running win32s.

• Static linking This mechanism works on all machines, but generally requires the same C-compiler and linker to be used for the external code as is used to build SWI-Prolog itself. This mechanism is the preferred way if shared libraries are not supported.

1Linux with the old a.out format does not

   • Using load foreign/2,5]

Basically only works on Unix system supporting the a.out format executables. This mechanism is slow and non-portable. It should be avoided whenever possible.

To make a runtime executable that can run on multiple platforms one must make runtime checks to find the correct way of linking. Suppose we have a source-file myextension defining the installation function install.

If this file is compiled to a shared library, load foreign library/1 will load this library and call the installation function to initialise the foreign code. If it is loaded as a static extension, define install() as the predicate install/0:

     static foreign_t
     pl_install()
     { install();
       PL_succeed;
     }
     PL_extension PL_extensions [] =
     {
     /*{ "name",     arity,  function,       PL_FA_<flags> },*/
       { "install",  0,      pl_install,     0 },
       { NULL,       0,      NULL,           0 }     /* terminating line */
     };

Now, use the following Prolog code to load the foreign library:

     load_foreign_extensions :-
             current_predicate(install, install), !, % static loaded
             install.
     load_foreign_extensions :-                      % shared library
             load_foreign_library(foreign(myextension)).
     :- initialization load_foreign_extensions.

The path alias foreign is defined by file search path/2. By default it searches the directories <home>/lib/<arch> and <home>/lib. The application can specify additional rules for

file search path/2.

6.3 Finding Application files

If your application uses files that are not part of the saved program such as database files, configuration files, etc., the runtime version has to be able to locate these files. The file search path/2 mechanism in combination with the -p command-line argument is the preferred way to locate runtime files. The first step is to define an alias for the toplevel directory of your application. We will call this directory gnatdir in our examples.

A good place for storing data associated with SWI-Prolog runtime systems is below the emulator’s home-directory. swi is a predefined alias for this directory. The following is a useful default definition for the search path.

     user:file_search_path(gnatdir, swi(gnat)).

The application should locate all files using absolute file name. Suppose gnatdir contains a file config.pl to define local configuration. Then use the code below to load this file:

     configure_gnat :-
             (   absolute_file_name(gnatdir('config.pl'), ConfigFile)
             ->  consult(ConfigFile)
             ;   format(user_error, 'gnat: Cannot locate config.pl~n'),
                 halt(1)
             ).

6.4 Using chpl for Configuration Information

6.4.1 Changing the emulator of a runtime application

The program chpl, may be used to manipulate the header of a SWI-Prolog bootfile or state created

with qsave program/[1,2].

It will be used most commonly by the installer of a SWI-Prolog runtime application to specify the path to the emulator. If the end-user decided to install the SWI-Prolog runtime environment in

     /usr/local/lib/rt-pl-2.1.4

the gnat application can be told to use this emulator using:

     % /usr/local/lib/rtpl-2.1.4/bin/chpl -e /usr/local/lib/rt-pl-2.1.4/bin/pl gnat

Now, gnat may be installed in any public or private directory for binaries.

6.4.2 Passing a path to the application

Suppose the system administrator has installed the SWI-Prolog runtime environment in /usr/local/lib/rt-pl-2.1.4. A user wants to install gnat, but gnat will look for its configuration in /usr/local/lib/rt-pl-2.1.4/gnat where the user cannot write.

The user decides to install the gnat runtime files in /users/bob/lib/gnat. For one-time usage, the user may decide to start gnat using the command:

     % gnat -p gnatdir=/users/bob/lib/gnat

For a more widely used executable, this is not very comfortable. The user may decide to edit the shell-script part of gnat. Upto the line holding

# End Header

gnat is a simple /bin/sh script. After this line, the file is binary and may contain long lines. Most editors are not capable of editing such files.^{2} Instead of editing the file directly, the program chpl may be used to extract and replace the header of gnat. The following editing sequence will work with any editor capable of editing ascii files.

% chpl -x gnat > gnat.hdr
% emacs gnat.hdr
% chpl -h gnat.hdr gnat

The header may be changed to the following to install gnat properly:

 #!/bin/sh
 # SWI-Prolog version: 2.1.4
 # SWI-Prolog save-version: 25
 exec ${SWIPL-/usr/local/lib/rt-pl-2.1.4/bin/pl} -x $0 \
      -p gnatdir=/users/bob/lib/gnat "$@"

6.5 The Runtime Environment

6.5.1 The Runtime Emulator

The sources may be used to built two versions of the emulator. By default, the development emulator is built. This emulator contains all features for interactive development of Prolog applications. If the system is configured using --enable-runtime, make will create a runtime version of the emulator. This emulator is equivalent to the development version, except for the following features:

• No input editing The GNU library -lreadline that provides EMACS compatible editing of input lines will never be linked to the system.

• No tracer The tracer and all its options are removed, making the system a little bit faster too.

• No profiler profile/3 and friends are not supported. This saves some space and provides a bit better performance.

• No interrupt Keyboard interrupt (Control-C normally) is not rebound and will normally terminate the application.

• feature(runtime, true) succeeds This may be used to verify your application is running in the runtime environment rather than the development environment.

2If you use GNU-Emacs, make sure require-final-newline is set to nil

• clause/[2,3] do not work on static predicates This feature inhibits listing your program. It is only a very limited protection however.

The following fragment is an example for building the runtime environment in $HOME/lib/rt-pl-2.1.4. If possible, the shared-library interface should be configured to ensure it can serve a large number of applications.

% cd pl-2.1.4
% mkdir runtime
% cd runtime
% ../src/configure --enable-runtime --enable-shared --prefix=$HOME
% make
% make rt-install

The runtime directory contains the components listed below. This directory may be tar’ed and shipped with your application.

README.RT  Info on the runtime environment
bin/pl  The emulator itself
bin/chpl  The utility to change the runtime
man/chpl.1 Manual page for chpl
man/pl.1  Manual page for pl
swipl  pointer to the home directory (.)
lib/  directory for shared libraries
lib/<arch>/ machine-specific shared libraries

CHAPTER 6. GENERATING RUNTIME APPLICATIONS 2.1 – 116 –

Appendix A

Hackers corner

This appendix describes a number of predicates which enable the Prolog user to inspect the Prolog environment and manipulate (or even redefine) the debugger. They can be used as entry points for experiments with debugging tools for Prolog. The predicates described here should be handled with some care as it is easy to corrupt the consistency of the Prolog system by misusing them.

A.1 Examining the Environment Stack

prolog current frame(-Frame)

Unify Frame with an integer providing a reference to the parent of the current local stack frame. A pointer to the current local frame cannot be provided as the predicate succeeds deterministically and therefore its frame is destroyed immediately after succeeding.

prolog frame attribute(+Frame, +Key, -Value)

Obtain information about the local stack frame Frame. Frame is a frame reference as obtained

through prolog current frame/1, prolog trace interception/3 or this predicate. The key

values are described in table A.1.

A.2 Intercepting the Tracer

prolog trace interception(+Port, +Frame, -Action)

Dynamic predicate, normally not defined. This predicate is called from the SWI-Prolog debugger just before it would show a port. If this predicate succeeds the debugger assumes the trace action has been taken care of and continues execution as described by Action. Otherwise the normal Prolog debugger actions are performed.

Port is one of call, redo, exit, fail or unify. Frame is an integer reference to the current local stack frame. Action should be unified with one of the atoms continue (just continue execution), retry (retry the current goal) or fail (force the current goal to fail). Leaving it a variable is identical to continue.

Together with the predicates described in section 3.36 and the other predicates of this chapter this predicate enables the Prolog user to define a complete new debugger in Prolog. Besides this it enables the Prolog programmer monitor the execution of a program. The example shown

APPENDIX A. HACKERS CORNER 2.1

Key  Value

alternative Value is unified with an integer reference to the local stack frame in which execution is resumed if the goal associated with Frame fails. Fails if the frame has no alternative frame.

has alternatives Value is unified with ‘1’ if Frame still is a candidate for

backtracking. ‘0’ otherwise.

goal Value is unified with the goal associated with Frame. If the definition module of the active predicate is not user the goal is represented as module:goal. Do not instantiate variables in this goal unless you know what you are doing!

clause Value is unified with a reference to the currently running clause. Fails if the current goal is associated with a foreign (C) defined predicate. See also nth clause/3 and

clause property/2.

level Value is unified with the recursion level of Frame. The top

level frame is at level ‘0’.

parent Value is unified with an integer reference to the parent local

stack frame of Frame. Fails if Frame is the top frame.

context module Value is unified with the name of the context module of

the environment.

top Value is unified with ‘1’ if Frame is the top Prolog goal from a recursive call back from the foreign language. ‘0’ otherwise.

Table A.1: Key values of prolog current frame/1

in figure A.1 records all goals trapped by the tracer in the database. To trace the execution of ‘go’ this way the following query should be given:

?- trace, go, notrace.

prolog_trace_interception(Port, Frame, continue) :-
prolog_frame_attribute(Frame, goal, Goal),
prolog_frame_attribute(Frame, level, Level),
recordz(trace, trace(Port, Level, Goal)).

Figure A.1: Record a trace in the database

prolog skip level(-Old, +New)

Unify Old with the old value of ‘skip level’ and than set this level according to New. New is an integer, or the special atom very deep (meaning don’t skip). The ‘skip level’ is a global variable of the Prolog system that disables the debugger on all recursion levels deeper than the level of the variable. Used to implement the trace options ‘skip’ (sets skip level to the level of the frame) and ‘up’ (sets skip level to the level of the parent frame (i.e. the level of this frame minus 1).

A.3 Exception Handling

A start has been made to make exception handling available to the Prolog user. On exceptions a dynamic and multifile defined predicate exception/3 is called. If this user defined predicate succeeds Prolog assumes the exception has been taken care of. Otherwise the system default exception handler is called.

exception(+Exception, +Context, -Action)

Dynamic predicate, normally not defined. Called by the Prolog system on run-time exceptions. Currently exception/3 is only used for trapping undefined predicates. Future versions might handle signal handling, floating exceptions and other runtime errors via this mechanism. The values for Exception are described below.

undefined predicate If Exception is undefined predicate Context is instantiated to a term Name/Arity. Name refers to the name and Arity to the arity of the undefined predicate. If the definition module of the predicate is not user, Context will be of the form Module:Name/Arity. If the predicate fails Prolog will print the default error warning and start the tracer. If the predicate succeeds it should instantiate the last argument either to the atom fail to tell Prolog to fail the predicate or the atom retry to tell Prolog to retry the predicate. This only makes sense if the exception handler has defined the predicate. Otherwise it will lead to a loop.

warning If prolog wants to give a warning while reading a file, it will first raise the exception warning. The context argument is a term of the form warning(Path, LineNo, Message), where Path is the absolute filename of the file prolog is reading; LineNo is an extimate of the line number where the error occurred and Message is a Prolog string indicating the message. The Action argument is ignored. The error is supposed to be presented to the user if the exception handler succeeds. Otherwise the standard Prolog warning message is printed. This exception is used by the library emacs interface, that integrates error handling with GNU-Emacs.

APPENDIX A. HACKERS CORNER 2.1 – 120 –

Appendix B

Summary

B.1 Predicates

! /0 Cut (discard choicepoints) ! /1 Cut block. See block/3 , /2{xfy 1000} Conjuction of goals

->   /2{xfy 1050}  If-then-else

. /2 Consult. Also list constructor ; /2{xfy 1100} Disjunction of goals. Same as | /2 < /2{xfx 700} Arithmetic smaller

=    /2{xfx  700}  Unification

=.. /2{xfx 700} “Univ.” Term to list conversion =:= /2{xfx 700} Arithmetic equal =< /2{xfx 700} Arithmetic smaller or equal

==   /2{xfx  700}  Identical

=@= /2{xfx 700} Structural identical =\= /2{xfx 700} Arithmetic not equal > /2{xfx 700} Arithmetic larger >= /2{xfx 700} Arithmetic larger or equal @< /2{xfx 700} Standard order smaller @=< /2{xfx 700} Standard order smaller or equal @> /2{xfx 700} Standard order larger @>= /2{xfx 700} Standard order larger or equal \+ /1{ fy 900} Negation by failure (argument not provable). Same as not/1

\=   /2{xfx  700}  Not unifyable
\==  /2{xfx  700}  Not identical

\=@= /2{xfx 700} Not structural identical ^/2{xfy 200} Existential quantification (bagof/3, setof/3) | /2{xfy 1100} Disjunction of goals. Same as ; /2

abolish/2 Remove predicate definition from the database abort/0 Abort execution, return to top level

absolute_file_name/2  Get absolute path name

APPENDIX B. SUMMARY 2.1

absolute_file_name/3 Get absolute path name with options access_file/2 Check access permissions of a file append/1 Append to a file append/3 Concatenate lists apply/2 Call goal with additional arguments apropos/1 library(online help): Show related predicates and manual sections arg/3 Access argument of a term arithmetic_function/1 Register an evaluable function assert/1 Add a clause to the database assert/2 Add a clause to the database, give reference asserta/1 Add a clause to the database (first) asserta/2 Add a clause to the database (first) assertz/1 Add a clause to the database (last) assertz/2 Add a clause to the database (last) at_halt/1 Register goal to run at halt/1 at_initialization/1 Register goal to run at start-up atom/1 Type check for an atom atom_char/2 Convert between atom and ASCII value atom_chars/2 Convert between atom and list of ASCII values atom_length/2 Determine length of an atom atom_to_term/3 Convert between atom and term atomic/1 Type check for primitive autoload/0 Autoload all predicates now

bagof/3 Find all solutions to a goal between/3 Integer range checking/generating block/3 Start a block (‘catch’/‘throw’) break/0 Start interactive toplevel

call/1 Call a goal call/[2..] Call with aditional arguments call_dll_function/2 Win32: Call function in dynamic link library (.dll file) call_shared_object_function/2 UNIX: Call C-function in shared (.so) file character_count/2 Get character index on a stream chdir/1 Change working directory checklist/2 Invoke goal on all members of a list clause/2 Get clauses of a predicate clause/3 Get clauses of a predicate clause_property/2 Get properties of a clause close/1 Close stream

close_dde_conversation/1  Win32: Close DDE channel

close_dll/1 Win32: Close dynamic link library (.dll file) close_shared_object/1 UNIX: Close shared library (.so file) compare/3 Compare, using a predicate to determine the order compiling/0 Is this a compilation run? compound/1 Test for compound term concat/3 Append two atoms concat_atom/2 Append a list of atoms consult/1 Read (compile) a Prolog source file context_module/1 Get context module of current goal convert_time/8 Convert time stamp copy_term/2 Make a copy of a term

current_arithmetic_function/1 Examine evaluable functions

current_atom/1 Examine existing atoms current_flag/1 Examine existing flags current_foreign_library/2 library(shlib): Examine loaded shared libraries (.so files) current_functor/2 Examine existing name/arity pairs current_input/1 Get current input stream current_key/1 Examine existing database keys current_module/1 Examine existing modules current_module/2 Examine existing modules current_op/3 Examine current operator declaractions current_output/1 Get the current output stream current_predicate/2 Examine existing predicates current_stream/3 Examine open streams

dde_current_connection/2 Win32: Examine open DDE connections dde_current_service/2 Win32: Examine DDE services provided dde_execute/2 Win32: Execute command on DDE server

dde_register_service/2  Win32: Become a DDE server

dde_request/3 Win32: Make a DDE request dde_unregister_service/1 Win32: Terminate a DDE service debug/0 Test for debugging mode debugging/0 Show debugger status default_module/2 Get the default modules of a module delete/3 Delete all matching members from a list delete_file/1 Remove a file from the file system discontiguous/1{fx 1150} Indicate distributed definition of a predicate display/1 Write a term, ignore operators display/2 Write a term, ignore operators on a stream displayq/1 Write a term with quotes, ignore operators displayq/2 Write a term with quotes, ignore operators on a stream dwim_match/2 Atoms match in “Do What I Mean” sense dwim_match/3 Atoms match in “Do What I Mean” sense dwim_predicate/2 Find predicate in “Do What I Mean” sense dynamic/1{fx 1150} Indicate predicate definition may change

ed/0 Edit last edited predicate ed/1 Edit a predicate edit/0 Edit last edited file edit/1 Edit a file edit_source/1 (hook) Intercept editing ensure_loaded/1 Consult a file if that has not yet been done erase/1 Erase a database record or clause exception/3 (hook) Handle runtime exceptions exists_directory/1 Check existence of directory exists_file/1 Check existence of file exit/2 Exit from named block. See block/3 expand_file_name/2 Wildcard expansion of file names expand_file_search_path/2 Wildcard expansion of file paths expand_term/2 Compiler: expand read term into clause(s) explain/1 library(explain): Explain argument explain/2 library(explain): 2nd argument is expalanation of first export/1 Export a predicate from a module export_list/2 List of public predicates of a module

fail/0 Always false fail/1 Immediately fail named block. See block/3 feature/2 Get system configuration parameters

file_base_name/2  Get file part of path

file_directory_name/2 Get directory part of path file_search_path/2 Define path-aliases for locating files fileerrors/2 Do/Don’t warn on file errors findall/3 Find all solutions to a goal flag/3 Simple global variable system flatten/2 Transform nested list into flat list float/1 Type check for a floating point number flush/0 Output pending characters on current stream flush_output/1 Output pending characters on specified stream forall/2 Prove goal for all solutions of another goal foreign_file/1 Examine loaded foreign files format/1 Formatted output format/2 Formatted output with arguments format/3 Formatted output on a stream

format_predicate/2  Program format/[1,2]

free_variables/2 Find unbound variables in a term functor/3 Get name and arity of a term or construct a term

garbage_collect/0 Invoke the garbage collector gensym/2 Generate unique atoms from a base get/1 Read first non-blank character get/2 Read first non-blank character from a stream get0/1 Read next character get0/2 Read next character from a stream get_single_char/1 Read next character from the terminal get_time/1 Get current time getenv/2 Get shell environment variable ground/1 Verify term holds no unbound variables

halt/0 Exit from Prolog halt/1 Exit from Prolog with status hash_term/2 Hash-value of ground term help/0 Give help on help help/1 Give help on predicates and show parts of manual history_depth/1 Number of remembered queries

ignore/1 Call the argument, but always succeed import/1 Import a predicate from a module index/1 Change clause indexing initialization/1 Initialization directive int_to_atom/2 Convert from integer to atom int_to_atom/3 Convert from integer to atom (non-decimal) integer/1 Type check for integer intersection/3 Set intersection is/2{xfx 700} Evaluate arithmetic expression is_absolute_file_name/1 True if arg defines an absolute path is_list/1 Type check for a list is_set/1 Type check for a set

keysort/2 Sort, using a key

last/2 Last element of a list leash/1 Change ports visited by the tracer length/2 Length of a list library_directory/1 (hook) Directories holding Prolog libraries limit_stack/2 Limit stack expansion line_count/2 Line number on stream line_position/2 Character position in line on stream list_to_set/2 Remove duplicates listing/0 List program in current module listing/1 List predicate load_foreign/2 Load foreign (C) module load_foreign/5 Load foreign (C) module load_foreign_library/1 library(shlib): Load shared library (.so file) load_foreign_library/2 library(shlib): Load shared library (.so file)

make/0 Reconsult all changed source files make_fat_filemap/1 Win32: Create file containing non-FAT filenames make_library_index/1 Create autoload file INDEX.pl maplist/3 Transform all elements of a list member/2 Element is member of a list

memberchk/2  Deterministic member/2

merge/3 Merge two sorted lists merge_set/3 Merge two sorted sets module/1 Query/set current type-in module module/2 Declare a module module_transparent/1{fx 1150} Indicate module based meta predicate msort/2 Sort, do not remove duplicates multifile/1{fx 1150} Indicate distributed definition of predicate

name/2 Convert between atom and list of ASCII characters nl/0 Generate a newline nl/1 Generate a newline on a stream nodebug/0 Disable debugging nonvar/1 Type check for bound term noprotocol/0 Disable logging of user interaction nospy/1 Remove spy point nospyall/0 Remove all spy points not/1{fy 900} Negation by failure (argument not provable). Same as \+ /1 notrace/0 Stop tracing nth0/3 N-th element of a list (0-based) nth1/3 N-th element of a list (1-based) nth_clause/3 N-th clause of a predicate number/1 Type check for integer or float number_chars/2 Convert between number and atom numbervars/4 Enumerate unbound variables of a term using a given base once/1 Call a goal deterministicaly op/3 Declare an operator open/3 Open a file (creating a stream)

open_dde_conversation/3  Win32: Open DDE channel

open_null_stream/1 Open a stream to discard output open_shared_object/2 UNIX: Open shared library (.so file)

phrase/2 Activate grammar-rule set phrase/3 Activate grammar-rule set (returning rest) please/3 Query/change environment parameters plus/3 Logical integer addition portray/1 (hook) Modify behaviour of print/1 portray_clause/1 Pretty print a clause predicate_property/2 Query predicate attributes predsort/3 Sort, using a predicate to determine the order preprocessor/2 Install a preprocessor before the compiler print/1 Print a term print/2 Print a term on a stream profile/3 Obtain execution statistics profile_count/3 Obtain profile results on a predicate profiler/2 Obtain/change status of the profiler prolog/0 Run interactive toplevel prolog_current_frame/1 Reference to goal’s environment stack prolog_frame_attribute/3 Obtain information on a goal environment prolog_load_context/2 Context information for directives prolog_skip_level/2 Indicate deepest recursion to trace prolog_to_os_filename/2 Convert between Prolog and OS filenames prolog_trace_interception/3 library(user): Intercept the Prolog tracer prompt1/1 Change prompt for 1 line prompt/2 Change the prompt used by read/1 proper_list/1 Type check for list protocol/1 Make a log of the user interaction protocola/1 Append log of the user interaction to file protocolling/1 On what file is user interaction logged put/1 Write a character put/2 Write a character on a stream

qcompile/1 Compile source to Quick Load File qload/1 Load Quick Load File as consult/1 qsave_program/1 Create runtime application qsave_program/2 Create runtime application read/1 Read Prolog term read/2 Read Prolog term from stream

read_clause/1  Read clause

read_clause/2 Read clause from stream read_history/6 Read using history substitution read_link/3 Read a symbolic link read_variables/2 Read clause including variable names read_variables/3 Read clause including variable names from stream recorda/2 Record term in the database (first) recorda/3 Record term in the database (first) recorded/2 Obtain term from the database recorded/3 Obtain term from the database recordz/2 Record term in the database (last) recordz/3 Record term in the database (last)

redefine_system_predicate/1 Abolish system definition

rename_file/2 Change name of file repeat/0 Succeed, leaving infinite backtrackpoints require/1 This file requires these predicates reset_profiler/0 Clear statistics obtained by the profiler

restore/1  Restore saved-state (save/1, save_program/1)

retract/1 Remove clause from the database retractall/1 Remove unifying clauses from the database reverse/2 Inverse the order of the elements in a list

same_file/2 Succeeds if arguments refer to same file save/1 Save program including current goal save/2 Save program including current goal save_program/1 Save the current program on a file save_program/2 Save the current program on a file see/1 Change the current input stream seeing/1 Query the current input stream seen/0 Close the current input stream select/3 Select element of a list set_feature/2 Define a system feature set_input/1 Set current input stream from a stream set_output/1 Set current output stream from a stream set_tty/2 Set ‘tty’ stream setarg/3 Destructive assignment on term setenv/2 Set shell environment variable setof/3 Find all unique solutions to a goal sformat/2 Format on a string sformat/3 Format on a string shell/0 Execute interactive subshell shell/1 Execute OS command shell/2 Execute OS command show_profile/1 Show results of the profiler size_file/2 Get size of a file in characters skip/1 Skip to character in current input skip/2 Skip to character on stream sleep/1 Suspend execution for specified time sort/2 Sort elements in a list source_file/1 Examine currently loaded source files source_file/2 Obtain source file of predicate source_location/2 Location of last read term spy/1 Force tracer on specified predicate stack_parameter/4 Some systems: Query/Set runtime stack parameter statistics/0 Show execution statistics statistics/2 Obtain collected statistics stream_position/3 Get/seek to position in file string/1 Type check for string string_length/2 Determine length of a string string_to_atom/2 Conversion between string and atom string_to_list/2 Conversion between string and list of ASCII style_check/1 Change level of warnings sublist/3 Determine elements that meet condition subset/2 Generate/check subset relation substring/4 Get part of a string subtract/3 Delete elements that do not meet condition succ/2 Logical integer successor relation swritef/2 Formatted write on a string swritef/3 Formatted write on a string

tab/1 Output number of spaces tab/2 Output number of spaces on a stream tell/1 Change current output stream telling/1 Query current output stream term_expansion/2 (hook) Convert term before compilation term_to_atom/2 Convert between term and atom time/1 Determine time needed to execute goal time_file/2 Get last modification time of file tmp_file/2 Create a temporary filename told/0 Close current output trace/0 Start the tracer trace/1 Set trace-point on predicate trace/2 Set/Clear trace-point on ports tracing/0 Query status of the tracer trim_stacks/0 Release unused memory resources true/0 Succeed

tty_get_capability/3  Get terminal parameter

tty_goto/2 Goto position on screen tty_put/2 Write control string to terminal ttyflush/0 Flush output on terminal

union/3 Union of two sets unknown/2 Trap undefined predicates unload_foreign_library/1 library(shlib): Detach shared library (.so file) unsetenv/1 Delete shell environment variable use_module/1 Import a module use_module/2 Import predicates from a module

var/1 Type check for unbound variable visible/1 Ports that are visible in the tracer volatile/1{fx 1150} Predicates that are not saved

wait_for_input/3 Wait for input with optional timeout wildcard_match/2 Csh(1) style wildcard match write/1 Write term write/2 Write term to stream write_ln/1 Write term, followed by a newline writef/1 Formatted write writef/2 Formatted write on stream writeq/1 Write term, insert quotes writeq/2 Write term, insert quotes on stream

B.2 Artihmetic Functions

* /2{yfx 400} Multiplication

+  /2{yfx 500}  Addition
-  /1{ fx 500}  Unary minus
-  /2{yfx 500}  Subtraction
/  /2{yfx 400}  Division

// /2{yfx 400} Integer division

/\ /2{yfx 500}  Bitwise and

<< /2{yfx 400} Bitwise left shift >> /2{yfx 400} Bitwise right shift "C"/1 (list of one character) Character code \ /1{ fx 500} Bitwise negation

\/ /2{yfx 500}  Bitwise or

^/2{xfy 200} Power function abs/1 Absolute value acos/1 Inverse (arc) cosine asin/1 Inverse (arc) sine atan/1 Inverse (arc) tangent atan/2 Rectangular to polar conversion ceil/1 Smallest integer larger than argument cos/1 Cosine cputime/0 Get CPU time e/0 Mathematical constant exp/1 Exponent (base e) floor/1 Largest integer below argument integer/1 Round to nearest integer log/1 Natural logarithm log10/1 10 base logarithm max/2 Maximum of two numbers min/2 Minimum of two numbers mod/2{xfx 300} Remainder of division random/1 Generate random number pi/0 Mathematical constant

sin/1  Sine

sqrt/1 Square root tan/1 Tangent xor/2{yfx 400} Bitwise exclusive or

B.3 Operators

1 fx $ Bind toplevel variable 200 xfy ^(1) Predicate 200 xfy ^(2) Arithmetic function 300 xfx mod Arithmetic function 400 yfx * Arithmetic function 400 yfx / Arithmetic function 400 yfx // Arithmetic function 400 yfx << Arithmetic function 400 yfx >> Arithmetic function 400 yfx xor Arithmetic function 500 fx + Arithmetic function 500 fx - Arithmetic function 500 fx ? XPCE: obtainer 500 fx \ Arithmetic function 500 yfx + Arithmetic function 500 yfx - Arithmetic function 500 yfx /\ Arithmetic function 500 yfx \/ Arithmetic function 600 xfy : module:term separator 700 xfx < Predicate 700 xfx = Predicate

700  xfx  =..  Predicate
700  xfx  =:=  Predicate

700 xfx =< Predicate 700 xfx == Predicate

700  xfx  =@=  Predicate
700  xfx  =\=  Predicate

700 xfx > Predicate 700 xfx >= Predicate 700 xfx @< Predicate

700  xfx  @=<  Predicate

700 xfx @> Predicate

700  xfx  @>=  Predicate

700 xfx is Predicate 700 xfx \= Predicate

700  xfx  \==  Predicate
700  xfx  \=@=  Predicate

900 fy not Predicate 900 fy \+ Predicate 1000 xfy , Predicate

1050  xfy  ->  Predicate

1100 xfy ; Predicate 1100 xfy | Predicate

1150   fx  discontiguous  Predicate
1150   fx  dynamic  Predicate
1150   fx  module_transparent Predicate
1150   fx  multifile  Predicate
1150   fx  volatile  Predicate
1150   fx  initialization  Predicate

1200 fx :- Introduces a directive 1200 fx ?- Introduces a directive 1200 xfx --> DCGrammar: rewrite 1200 xfx :- head :- body. separator

Bibliography

[Anjewierden & Wielemaker, 1989] A. Anjewierden and J. Wielemaker. Extensible objects. ESPRIT Project 1098 Technical Report UvA-C1-TR-006a, University of Amsterdam, March 1989.

[BIM, 1989] BIM Prolog release 2.4. Everberg, Belgium, 1989.

[Bowen & Byrd, 1983] D. L. Bowen and L. M. Byrd. A portable Prolog compiler. In L. M. Pereira, ed., Proceedings of the Logic Programming Workshop 1983, Lisabon, Portugal, 1983. Universidade nova de Lisboa.

[Bratko, 1986] I. Bratko. Prolog Programming for Artificial Intelligence. Addison-Wesley, Reading MA, 1986.

[Clocksin & Mellish, 1981] W. F. Clocksin and C. S. Mellish. Programming in Prolog. Springer-Verlag, New York, 1981. [4th ed. 1994]

[Kernighan & Ritchie, 1978] B. W. Kernighan and D. M. Ritchie. The C Programming Language. Prentice-Hall, Englewood Cliffs NJ, 1978.

[O’Keefe, 1985] R. A. O’Keefe. This Here Isn’t Even Fine, 1985. Also available from SWI, University of Amsterdam.

[O’Keefe, 1990] R. A. O’Keefe. The Craft of Prolog. MIT Press, Cambridge MA, 1990.

[Pereira, 1986] F. Pereira. C-Prolog User’s Manual, 1986.

[Qui, 1987] Quintus Prolog, User Guide and Reference Manual. Mountain View CA, 1987.

[Sterling & Shapiro, 1986] L. Sterling and E. Shapiro. The Art of Prolog. MIT Press, Cambridge MA, 1986. [2nd ed. 1994]

[Warren, 1983] D. H. D. Warren. The runtime environment for a Prolog compiler using a copy algorithm. Technical Report 83/052, SUNY and Stone Brook, New York, 1983. Major revision March 1984.