Search code examples
prologswi-prologiso-prolog

Prolog - check the end of the stream doesn't work


I have a file memo.dat , with these terms:

memo(verdi,11).
memo(rossi,7).
memo(bianchi,9).
memo(blu,7).
memo(neri,11).
memo(carli,11).
memo(rapini,8).

I wrote a prolog program in order to obtain a set of tuples from this file:

memo_to_list(MemoList):-
    open('/home/ale/Downloads/Prolog_exercises/memo.dat',read,Stream),
    read_list_from_stream(Stream,MemoList),
    close(Stream).

read_list_from_stream(Stream,[]):-
    at_end_of_stream(Stream),!.

read_list_from_stream(Stream,[(Cognome,Ora)|RestoAppuntamenti]):-
    read(Stream,memo(Cognome,Ora)),
    read_list_from_stream(Stream,RestoAppuntamenti).

However, the predicate at_end_of_stream fails to check when the stream reaches its end. What can be the problem ? (I used the ubuntu default text editor to create the file memo.dat)


Solution

  • The end of the stream is only detected when you actually reach it. When you read the last fact, the end-of-file marker have yet to be read. Try instead something like:

    memo_to_list(MemoList):-
        open('/home/ale/Downloads/Prolog_exercises/memo.dat',read,Stream),
        read(Stream,Term),
        read_list_from_stream(Term,Stream,MemoList),
        close(Stream).
    
    read_list_from_stream(end_of_file,_,[]) :-
        !.
    
    read_list_from_stream(memo(Cognome,Ora),Stream,[(Cognome,Ora)|RestoAppuntamenti]):-
        read(Stream,Term),
        read_list_from_stream(Term,Stream,RestoAppuntamenti).
    

    You can also avoid leaking stream handles and unclosed streams in case something is wrong with your data file by using the setup_call_cleanup/3 built-in predicate:

    memo_to_list(MemoList) :-
        setup_call_cleanup(
            open('/Users/pmoura/Desktop/memo.dat',read,Stream),
            (   read(Stream,Term),
                read_list_from_stream(Term,Stream,MemoList)
            ),
            close(Stream)
        ).
    

    Update

    The Prolog standard requires that the . that ends a term is followed by a layout character. Your code only works if there isn't any character (other than the end-of-file) after the last dot of the last term, which makes the Prolog text non-conforming but, depending on the Prolog system, may allow the end of stream to be detected by calling the at_end_of_stream /1 predicate after reading the last term. Note also that's common for text editors to add a new-line after the last line of text if not present on saving. That new-line is a layout character as required by the Prolog standard. Therefore, for a compliant, reliable, and portable solution, make sure there's a new line at the end of your data file and use a solution along this answer.