For some tasks you can save space by using failure driven loops.
For example, suppose we want to write a predicate,
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
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:- 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)).