A pair of directives
:- if(:Goal). ... :- endif.
will evaluate Goal and, if the goal succeeds, the sentences
between the if/1
directive and the matching endif/0
directive will be processed as usual.
If the evaluation of Goal does not succeed, i.e. fails or raises
an exception, the sentences between the if/1
directive and the
endif/0
directive are completely ignored, except that any
conditional directives must be properly nested. In particular, term
expansion will not be performed on such ignored sentences and the goals
of any nested conditional directives will not be evaluated.
The full form of conditional compilation directives include
optional else/0
and elif/1
and are used as follows
:- if(:Goal1). ... :- else. ... :- endif.
If the goal of the if/1
directive succeeds, the sentences up
to the matching else/0
directive are processed as usual.
Otherwise, if the goal fails or raises an exception, the sentences between
the else/0
directive and the matching endif/0
directive are
processed as usual.
Finally, elif/1
is available as a shorthand for nested uses of
if/1
and else/0
:- if(:Goal1). ... :- elif(:Goal2). ... :- elif(:Goal3). ... :- else. ... :- endif.
will evaluate the goals in turn, until one of them succeeds in which
case the following sentences will be processed as usual up to the
corresponding else/0
, endif/0
or elif/1
.
A valid sequence of conditional compilation directives
must contain exactly one if/1
directive followed by zero or more
elif/1
directives followed by at most one else/0
directive
followed by exactly one endif/0
directive. Valid sequences of
conditional directives can be nested.
All directives that make up a sequence of conditional compilation
directives must be in the same file. For instance, you cannot have a
if/1
directive in one file and then have the corresponding
endif/0
directive in a file included with an include/1
directive. Nested conditional compilation sequences can of course be
located in included files.
Conditional compilation directives are handled very early in the
processing of an input file. In particular, term expansion hooks will
never see if/1
, else/0
, elif/1
or endif/0
directives. Also, neither of if/1
, else/0
, elif/1
or endif/0
are defined as predicates.
If evaluation of a goal for if/1
directive or an elif/1
directive raises an exception, an error message will be written and the goal
will be treated as if it failed.
Conditional compilation is useful for writing portable Prolog code
since it makes it possible to adapt to peculiarities of various
implementations. The Prolog flag dialect
, used by several
Prolog implementations, is especially useful here.
:- if(current_prolog_flag(dialect, sicstus). %% We are being compiled in SICStus %% Only SICStus has this library :- use_module(library(process), [process_create/2]). :- elif(current_prolog_flag(dialect, othervendor)). %% We are being compiled in Other Vendor, we need to provide our own %% compatibility layer :- use_module(...). process_create(A,B) :- ... :- else. %% We are being compiled in some unknown Prolog, give up. process_create(_,_) :- throw(not_implemented). :- endif.
Another possible usage is for disabling, perhaps costly, debugging code when building an optimized version of the code.
%% Only need environ/2 at compile-time for conditional compilation :- load_files(library(system), [when(compile_time), imports([environ/2])]). :- if(\+ environ(optimize, true)). %% This clause does some expensive sanity checks. Disabled when building %% an optimized version. foo(X) :- \+ valid_x(X), throw(invalid_x(X)). :- endif. %% This clause is always present. foo(X) :- do_x_things(X).
Invoking the SICStus development system with an option
-Doptimize=true, to set the system property optimize
,
and then compiling the above code will ensure that the first, sanity
checking, clause is not part of the foo/1
predicate. Invoking the
development system without such an option will ensure that the sanity
checking clause is part of the foo/1
predicate.