next up previous
Next: Useful Tip 6 Up: Efficiency Considerations Previous: Useful Tip 4

Useful Tip 5

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)).



Dave Stuart Robertson
Tue Jul 7 10:44:26 BST 1998