Modular Programming

A Visual Prolog program can be broken up into modules. You can write, edit, and compile the modules separately, and then link them together to create a single executable program. If you need to change the program, you only need to edit and recompile individual modules, not the entire program--a feature you will appreciate when you write large programs. Also, modular programming allows you to take advantage of the fact that, by default, all predicate and domain names are local. This means different modules can use the same name in different ways. Visual Prolog uses two concepts to manage modular programming: projects and global declarations. Among other things, these features make it possible to keep a record of which modules make up a program (this record is called a project), and to perform type-checking across module boundaries. In this section, we'll define the two concepts; then, using a simple example, we'll show you how some modules can be combined into a single, stand-alone program.

1. Global Declarations

By default, all names used in a module are local. Visual Prolog programs communicate across module boundaries using the predicates defined in the global predicates and global database sections. The domains used in these global sections must be defined as global domains, or else they must be pre-defined domains.

ALL THE MODULES IN A PROJECT NEED TO HAVE EXACTLY THE SAME GLOBAL DATABASE AND GLOBAL DOMAINS DECLARATIONS.

If you mix this up, all sorts of strange things will probably happen, such as a hung computer under DOS or MS Windows, or a protection violation on other platforms.

The easiest way to ensure this is correct is by writing all global declarations in a single file, which you can then include in every relevant module with an include directive. For example, if all your global declarations are in a file called global.inc, you can include that file in every relevant module by adding the directive:

    include "global.inc"

to the top of each module.

All global declarations must appear before any local declarations local declarations.

(1) Global Domains

You make a domain global by writing it in a global domains section. In all other respects, global domains are the same as ordinary (local) domains.

Note: If any global domain definition is changed, all modules in that project must be recompiled.

(2) Global Database

You make a database section global to a project by preceding the database keyword with the keyword global. You can only give initializing facts for global databases in the main module, which is the one containing the goal section. The goal section must appear before the global database clauses in the main module.

Note: If any global database definition is changed, all modules in that project must be recompiled.

(3) Global Predicates

Global predicate declarations differ from ordinary (local) predicate declarations because they must contain a description of the flow pattern(s) by which each given predicate can be called. If such one is not specified, all arguments will be input. The syntax for a global predicate declarations is:

    [ { determ | nondeterm | single | nocopy} ] [ domain ] name arglist
       [ - flowpattern [ [,] flowpattern ]* ] [ language ] [ namespec ]

(curly braces indicate "choose one", square brackets indicate optional items) where

Note, that predicate types can also appear before the flowpattern.

    domain is the return domain, if you're declaring a function
    name is the name of the predicate
    arglist is of the form
        ( [ domain [ , domain ]* ] )

flowpattern is of the form
    ( flow [ , flow ]* )
where flow is
    { i | o | functor flowpattern | listflow }
where listflow is
   '[' flow [ , flow ]* [ '|' { i | o | listflow } ] ']'

    language is of the form
        language { c | asm | pascal | prolog | stdcall | syscall }

    namespec is of the form
        as "extname"

The namespec may be used to specify the public object-code name, overriding the default naming used by Visual Prolog. The main use of this is when you're linking in modules written in other languages.

The language directs the calling convention used when calling the predicate. This defaults to "prolog".

In the following global predicate declaration, name and home are of type string, and age is of type integer; the arguments to first_pred can either be all bound (i, i, i) or all free (o, o, o):

first_pred(name,home,age) - (i,i,i) (o,o,o)

Here is the declaration for a predicate with either compound flow of an integer list, or plain output flow:

p1(integerlist) - ([i,o,i|o]),(o)

Finally, this declaration specifies compound flow for an object declared as func(string,integer) coming from a domain called mydom:

pred(mydom) - (func(i,o)) (func(o,i))

Note: If any global predicate definition is changed, only the modules that refer to this predicate need to be recompiled. However, it is rather critical that this recompilation is done; if you change the flow pattern of a predicate the calls using it will need different code.

It doesn't matter in which module the clauses for global predicates appear, but--as with local predicates--all clauses must appear together.