Loads libraries and code in the following modes
?- pack_install( requires ).
?- use_module( library(requires) ).
The following is a synonymous way of loading the library
?- use_module( library(lib) ).
The library provides two directive predicates for loading code lib/1 and requires/1.
Originally, requires/1 was used for locating and loading predicates with
?- requires( kv_decompose/3 )
and lib/1 was developed to be a packs aware synonym of
use_module(library(Pack))
, such as
?- lib(lists). ?- lib(bims).
where lists is the system library traditionally loaded with use_module(library(lists))
and bims
is an installed pack.
If the argument to lib/1 is not an installed library, then the predicate will look on the SWI server for installable packs.
?- lib(switex). % Contacting server at http://www.swi-prolog.org/pack/query ... ok p switex@0.0.7 - Literate programming with LaTeX and Prolog Lib not found, but pack exists, do you want me to run ?- pack_install(switex). Y/n?
As the arguments described so far for requires/1 and lib/1 can be distinguished, lib/1 can also act as a synonym to requires:
?- lib( kv_decompose/3 ).
is identical to
?- requires( kv_decompose/3 ).
The main idea of pack(requires)
is that the top of a source file contains a number of
directives declaring dependencies to other source files. The pack works particularly well
with predicate-in-single-file development where, for instance, kv_cecompose/3 is defined
in src/lib/kv_decompose.pl
. pack(requires)
also works with index files (LibIndex.pl
) that
can point where specific predicates are located.
By default pack(requires)
look into the following sub-directories for source code:
By default requires/1 loads code by either
(a) looking into src/LibIndex.pl
for a pointer to the file defining a specific predicate, or
(b) searching for a file whose name matches the name of the to-be-loaded predicate.
Under scenario (a) above, a directive such as
:- requires( kv_decompose/3 ).
will match entry of LibIndex.pl
lib_index(kv_decompose, 3, any, user, 'lib/kv/kv_decompose').
and load file src/lib/kv/kv_decompose.pl
.
Under scenario (b)
:- requires( kv_decompose/3 ).
will match the predicate name to the filename kv_decompose.pl
and load the file.
pack(requires)
can be used to load specific predicates from packs that use the
requires methodology. This can be done without loading the whole of the external pack.
A good example of a pack allowing partial loading is stoics_lib.
From there one can load a single predicate and its dependencies without loading the whole of the library
with something like
?- requires( stoics_lib:kv_decompose/3 ).
and
?- lib( stoics_lib:kv_decompose/3 ).
The indices of all installed packages that contain src/LibIndex.pl
can be made available
to the system when library(requires)
is loaded if the flag lib_indices is set to true:
?- set_prolog_file( lib_indices, true ).
or by calling
?- lib_load_pack_index.
which loads all available indices, or with
?- lib_load_pack_index( +Pack ).
which loads index for specific Pack
.
Indices are loaded on predicate lib_index: pack_lib_index/4. Once the index of a pack has been consulted, its predicates can be loaded without prefixing.
?- lib_load_pack_index( stoics_lib ). ?- requires( kv_decompose/3 ).
The pack also allows index based access to directories containg code. Particularly code that is fragmented and follows a single-entry-predicate-per-file. The main use scenario is that of declaring a number of directories as code repositories in a users Prolog start up file. Any Prolog session will then have easy access to loading the predicates within those directories.
As an example, assume source Prolog files are kept in ~/pl/lib. An index of all predicates can be created by
?- expand_file_name( '~/pl/src', PlSrc ), lib_mkindex( PlSrc ).
Assuming there is file term/en_list.pl
defining en_list/2, then the above will create entry
lib_index(en_list, 2, any, user, 'lib/term/en_list').
Once the user enters the following directive to their initialisation file
?- expand_file_name('~/pl/src',PlLib), assert(library_directory(PlLib)).
then loading pack(requires)
will assert
lib_index(en_list, 2, any, user, 'lib/term/en_list').
and the user will be able to load the predicate with
?- requires( en_list/2 ).
Indices that are used to locate code within subdirecdtories can be created for directories and packs with
?- lib_mkindex( DirOrPack).
For packs, the main idea is that during development the system might rely on the filenames to locate loadable code where as before publication an index can be created.
See also lib_mkindex/0.
The library defines flag lib_homonym (Boolean) which controls whether the library seeks to load code by matching predicate names to filenames (see also lib_pack_start/2).
This library is now in beta. Internally things might change, but interface should be stable.
Used at the beginning of load sections (lib_pac_start/1) of a main pack file
to signify that all local requires()
calls should be interpretted as loads
from Pack and at end of load sections (lib_pack_end/1) to release the lock.
This should not be necessary, but SWI 7.3.31-9-g57cb567
looses the prolog_load_context(module,_)
when requires/1 is called
from different file (even though we are loading within the correct module).
Homonym is a Boolean value stating whether requires will try to load predicate definitions from a file having the same name whithin the file structure of the pack or library directory.
Originally the predicate facilitated loading predicates from a lib directory with the explicit purpose of allowing publication of source code that included all necessary lib code. With the advent of packs the paradigm has shifted but the main idea remains that of predicate-in-a-file software development.
The predicate should be used as a declaration at the top of a file declaring dependencies to other predicates. For instance in the following example current_call/2 depends on goal_spec/2.
:- requires( stoics_lib:goal_spec/2 ). current_call( Goal ) :- current_call( Goal, fail ). current_call( Goal, _Else ) :- goal_spec( Goal, Spec ), current_predicate( Spec ), !, call( Goal ). current_call( _Goal, Else ) :- call( Else ).
When PPindicator is of the form Pname/Arity where Pname is atomic and Arity is a positive integer requires/1 looks in the following places:
Pack:Pname/Arity if Pack is the current context from which requires/1 was asked to load a parent of the predicate (see below) or if Pack is a current moduled pack into which code is to be loaded
lib_index:pack_lib_index(Pname,Arity,Pack,File)
lib_index:lib_index(Pname,Arity,_,_,File)
lib_index/5, is loaded from <library>/LibIndex.pl
files. This corresponds to the original design
where the only difference between public and private versions were the underlying location of the
library directory.
When PPindicator is of the form Pack:Pname/Arity is loaded from Pack's sources. The following order is used to locate the appropriate file
lib_index(Pname,Arity,_,_,File)
src/LibIndex.pl
and checking as aboveIf a predicate is already defined, there is no effort to verify that is loaded from any particular source. When debugging is turned on and info message will indicate the absolute location for the original source.
src/LibIndex.pl
then its clauses
are loaded into module lib_index
. Else, the predicate succeeds without
any actions. Loading of the clauses make them available for loading without prefixing.
?- requires( stoics_lib:kv_decompose/3 ). ?- kv_decompose([a-1,b-2,c-3], Ls, Ns ). Ls = [a, b, c], Ns = [1, 2, 3].
compared to
?- requires( kv_compose/3 ). ERROR: Cannot locate predicate: kv_compose/3, in pack context: none and into: user false. ?- lib_load_pack_index( kv_compose/3 ). ?- lib_load_pack_index( stoics_lib ). ?- requires( kv_decompose/3 ).
Opts (can be unlisted)
prolog/Pack.pl
exists, shall we consult it before creating the index ?Currently the predicate assumes that
(a) Pack/prolog/Pack.pl
is the only prerequisite to loading Pack files to memory, and
(b) that there is a src/ subdirectory.
The predicate uses loading of code and predicate_property
calls to do all the heavy lifting. It thus creates file
Pack/src/LibIndex.pl
.
==
?- lib_mkindex( local_lib_dir, true )
.
?_ lib_mkindex( options, true )
. % make index for pack(options)
deposited stc/LibIndex.pl
?- lib_mkindex(
++
use_module(library(Lib))
. Libs is a list of library names.
In addition if current_prolog_flag(debug_initialization,true)
succeeds, debug(Lib)
is internally turned on for the load operation.
Finally if Lib is not installed pack, the predicate suggests loading it.
?- lib( bio_db ). ?- halt. % swipl -f ?- use_module( library(requires) ). ?- set_prolog_flag( debug_initialization, true ). ?- lib( bio_db ).
For each Pind in PindS (list or single predicate specification), the predicate does nothing if a matching predicate is defined in memory, else it prints a warning.
The raison d'ĂȘtre is to flag upstream loading one from possibly many alternatives implementation of a predicate that the current predicate depends on.
For example, see k_sub_graph/5. There, the native predicate depends on sub_graph/3. Irrespective of how graphs are represented k_sub_graph/5 only needs access to sub_graph/3 to do its job. Therefore the following directive is added to the source of k_sub_graph/5:
:- lib_expects( sub_graph/3 ).
?- lib_expects( nothing/0 ). % Warning: Expected predicate nothing/0, not in memory ?- use_module( library(lists) ). ?- lib_expects( append/3 ). true.
Currently Expects should be of the form lib(Lib)
.
expects/2 will attempt to load Lib via use_module(library(Lib))
.
If that fails a warning containing Mess will be printed and Call
will be called. Call usually defines operators that allow
the rest of the code to compile without errors.
The idea is to flag missing components and describe in the message which part of a pack will be affected, but do not stop the loading as the core functionality of a pack is not affected.
To get the warning messages about missing expected libs, set the flag
?- set_prolog_flag( lib_expects_report, true ).