Modules

Modules are supported according to the ISO Prolog standard. For a quick start, see the file samples/prolog/duckworld/duckym.pro. It is a version of the duck world tutorial sample that uses modules.

A module is a named collection of predicates. A module can import predicates from other modules, and can export predicates for other modules to use.

Default User Module

If a program does not have any module directives, then, by default, all of the predicates are defined in a default module named 'user'.

All of the predicates in module 'user' are automatically visible from all other modules.

System Module

All of the built-in predicates of the system are in a special system module, that is automatically visible from all other modules.

Defining Modules

It is possible to separate the definition of a module from the body of the module, where the predicates are defined. The definition of a module starts with the directive

:- module(M).

where M is the name of the module, and ends with

:- end_module(M).

The two directives both need to be specified.

Adding Predicates to a Module

The body of a module is bracketed between the directives

:- body(M).
:- end_body(M).

where M is the name of the module.

The body directives are optional, and the predicates of a module can be included between the module/end_module pair instead. (This is a non-ISO extension in Amzi!)

Referring to Modules

The colon notation is used to explicitly refer to a predicate in another module. It is

MODULE:FUNCTOR(ARG1, ... ARGN)

For example,

assert( data:loc(egg,pen) )

asserts a loc/2 clause in the 'data' module.

Exports

The export directive is used to define the external interface to a module, that is, the predicates which can be called from other modules. The exports are part of the module definition.

:- export(F/A).

or

:- export([F1/A1, F2/A2, ...Fn/An]).

For example, these directives define a module, 'data', that exports two predicates.

:- module(data).
:- export( [nextto/2, loc/2] ).
:- end_module(data).

Imports

A module can either import another module or specific predicates using the import directive. This lets it refer to those predicates without module qualification.

:- import(list).

This lets the calling module see all the exported predicates from the module 'list'.

:- import( [list:member/2, list:append/3] ).

Lets a module see the two specific predicates in the module 'list'.

Metapredicates

Metapredicates are of interest only to those programmers writing predicates whose arguments are themselves predicates.

Modules create a problem with predicates whose arguments are themselves intended to be predicates. Ideally those predicate arguments should refer to predicates in the calling module, not the defining module for the predicate.

Consider, for example, the system predicate assert/1. It is defined in the system module, but its argument typically refers to a clause in the module in which it is used.

For example

:- module(data).
add(fact(X)) :-
  assert(fact(X)).

In this example, you would expect the assert to assert fact(X) in the 'data' module, which it does, even though assert/1 is defined in a different module.

Predicates with this property are called metapredicates, and the arguments that are context sensitive are called metaarguments. They are specified with the metapredicate directive. The metaarguments are indicated by the ':' symbol, other arguments by the '*' symbol.

For example, the system metapredicates assert/1 and clause/3 have these directives declared for them.

:- metapredicate(assert(:)).
:- metapredicate(findall(*,:,*)).

An example of some user code that might require a metapredicate definition is a tracing predicate. For example.

:- module(trace).
:- export(tr/1).
:- metapredicate(tr(:)).
tr(X) :-
   (write(call-X),nl; write(fail-X),nl,fail),
   call(X),
   (write(exit-X),nl; write(redo-X),nl,fail).
:- end_module(trace)

This module could then be used to help debug another module with code like this.

:- module(buggy).
:- import(trace).
a(X) :-
   tr( b(X) ).
b(X) :-
   something.
...
:- end_module(buggy).

Because tr/1 is a metapredicate, the call uses the b/1 definition in module 'buggy', instead of looking for one in module 'trace'.

Copyright ©1987-2011 Amzi! inc. All Rights Reserved. Amzi! is a registered trademark and Logic Server is a trademark of Amzi! inc.