Пролог - проверка конца потока не работает

У меня есть файл 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)


person Koinos    schedule 28.08.2018    source источник


Ответы (1)


Конец потока обнаруживается только тогда, когда вы действительно его достигаете. Когда вы читаете последний факт, маркер конца файла еще не прочитан. Вместо этого попробуйте что-то вроде:

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 требует, чтобы за ., заканчивающим термин, следовал символ макета. Ваш код работает только в том случае, если нет никакого символа (кроме конца файла) после последней точки последнего термина, что делает текст Пролога несоответствующим, но, в зависимости от системы Пролога, может разрешить конец потока, который нужно обнаружить, вызвав предикат at_end_of_stream /1 после чтения последнего термина. Также обратите внимание, что текстовые редакторы обычно добавляют новую строку после последней строки текста, если она отсутствует при сохранении. Эта новая строка является символом макета, как того требует стандарт Пролога. Поэтому для совместимого, надежного и переносимого решения убедитесь, что в конце файла данных есть новая строка, и используйте решение вместе с этим ответом.

person Paulo Moura    schedule 28.08.2018
comment
Большое спасибо. В любом случае мой код тоже должен работать. Возможно проблема в текстовом редакторе. Программа, которую я написал, является стандартной, поэтому она должна работать... - person Koinos; 29.08.2018
comment
Обновил мой ответ с расширенным объяснением. - person Paulo Moura; 29.08.2018
comment
Спасибо, я изменил редактор (Notepadqq), и теперь он работает :) - person Koinos; 29.08.2018
comment
Считаете ли вы, что такое поведение at_end_of_steam/1 соответствует требованиям? Не лучше ли проверить, есть ли еще что почитать? SWI сделал это некоторое время назад. - person false; 03.09.2018