For some tasks you can save space by using failure driven loops.
For example, suppose we want to write a predicate, read_file/1
,
which will read each clause, C
, from a given file and assert them
into the database as a series of facts of the form cl(C)
. The first
part of this predicate takes care of opening the file; calling the
subgoal, read_all_clauses
, which does the reading and asserting;
and closing the file at the end.
read_file(File):- open(File, read, Stream), set_input(Stream), read_all_clauses, close(Stream).We could write a recursive definition of
read_all_clauses/0
:
read_all_clauses:- read(Clause), ((Clause = end_of_file, !) ; (assert(cl(Clause)), read_all_clauses)).But a failure driven version will be more efficient:
read_all_clauses:- repeat, read(Clause), ((Clause = end_of_file, !) ; (assert(cl(Clause)), fail)).