Prolog - 检查流的结尾不起作用

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

我有一个文件 memo.dat ,其中包含以下条款:

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

为了从这个文件中获取一组元组,我写了一个序言程序:

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

但是,谓词 at_end_of_stream 无法检查流何时到达终点。可能是什么问题? (我使用 ubuntu 默认文本编辑器创建文件 memo.dat

流的结尾只有在您实际到达时才会被检测到。当您读取最后一个事实时,文件结束标记尚未读取。试试像这样的东西:

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

如果您的数据文件出现问题,您还可以通过使用 setup_call_cleanup/3 内置谓词来避免泄漏流句柄和未关闭的流:

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

更新

Prolog 标准要求结束术语的 . 后跟布局字符。您的代码仅在最后一项的最后一个点之后没有任何字符(文件结尾除外)时才有效,这使得 Prolog 文本不符合要求,但根据 Prolog 系统,可能允许结束在读取最后一项后通过调用 at_end_of_stream /1 谓词来检测流的数量。另请注意,如果保存时不存在,文本编辑器通常会在最后一行文本后添加一个换行符。该换行符是 Prolog 标准要求的布局字符。因此,对于合规、可靠且可移植的解决方案,请确保在数据文件末尾有一个新行,并根据此答案使用解决方案。