There is an efficiency advantage in using conditionals whose test part
consists only of arithmetic comparisons or type tests. Consider the
following alternative definitions of the predicate
type_of_character/2
. In the first definition, four clauses
are used to group characters on the basis of arithmetic comparisons.
type_of_character(Ch, Type) :- Ch >= "a", Ch =< "z", !, Type = lowercase. type_of_character(Ch, Type) :- Ch >= "A", Ch =< "Z", !, Type = uppercase. type_of_character(Ch, Type) :- Ch >= "0", Ch =< "9", !, Type = digit. type_of_character(_Ch, Type) :- Type = other.
In the second definition, a single clause with a conditional is used. The compiler generates equivalent, optimized code for both versions.
type_of_character(Ch, Type) :- ( Ch >= "a", Ch =< "z" -> Type = lowercase ; Ch >= "A", Ch =< "Z" -> Type = uppercase ; Ch >= "0", Ch =< "9" -> Type = digit ; otherwise -> Type = other ).
Following is a list of built-in predicates that are compiled efficiently in conditionals:
atom/1
atomic/1
callable/1
compound/1
float/1
ground/1
integer/1
nonvar/1
number/1
simple/1
var/1
</2
=</2
=:=/2
=\=/2
>=/2
>/2
@</2
@=</2
==/2
\==/2
@>=/2
@>/2
This optimization is actually somewhat more general than what is described above. A sequence of guarded clauses:
Head1 :- Guard1, !, Body1. ... Headm :- Guardm, !, Bodym. Headn :- Bodym.
is eligible for the same optimization, provided that the arguments of the clause heads are all unique variables and that the "guards" are simple tests as listed above.