Сохранить объект в файл в Logtalk
Я написал проект пролога, и теперь я должен изменить его на файл Logtalk. В коде я могу утверждать новые факты в другой файл пролога с кодом:
:- dynamic(student/5).
:- use_module(library(persistency)).
:- persistent(student(id, name, surname, mark, studies)).
:- initialization(db_attach('student_database.pl', [])).
add_student(ID, Name, Surname, Mark, Studies):-
with_mutex(student_db, assert_student(ID, Name, Surname, Mark, Studies)).
Теперь я хочу сделать что-то похожее в Logtalk, но не с фактами, а с объектами. Ofc я знаю, как сделать новый объект create_object/4
с протоколом), но я не знаю, как сохранить его в файл в качестве базы данных.
Протокол выглядит так:
:- protocol(student).
:- public([
id/1,
name/1,
surname/1,
studies/1,
marks/1
]).
:- end_protocol.
Может ли кто-нибудь помочь мне с сохранением этих объектов?
1 ответ
Сериализация динамических объектов в целом может быть сложной в зависимости от зависимостей объектов, но ваш случай кажется более простым, поскольку каждый объект зависит только от одного протокола и содержит только факты.
При использовании серверной системы Prolog, которая поддерживает сохраненные состояния (например, SICStus Prolog, SWI-Prolog или YAP), простым решением является создание сохраненного состояния. Поскольку не существует стандарта для сохраненных состояний, это решение обязательно непереносимо.
Когда сохраненные состояния невозможны или ищется переносимое решение, нам нужно определить формат для сохраненных данных, чтобы мы могли интерпретировать их при загрузке и восстанавливать объекты. Давайте предположим, что мы хотим восстановить объекты как динамические объекты (так как они были изначально созданы с использованием create_object/4
предикат) и использовать простое представление, data/1
, для сохраненного состояния. Мы можем определить общий serializer
объект следующим образом (не проверено):
:- object(serializer).
:- public([
save/2,
restore/1
]).
save(Protocol, File) :-
protocol_property(Protocol, public(Predicates)),
open(File, write, Stream),
write_canonical(Stream, protocol(Protocol)), write(Stream, '.\n'),
forall(
conforms_to_protocol(Object, Protocol),
save_object(Object, Predicates, Stream)
),
close(Stream).
save_object(Object, Predicates, Stream) :-
object_data(Predicates, Object, [], Data),
write_canonical(Stream, data(Data)), write(Stream, '.\n').
object_data([], _, Data, Data).
object_data([Functor/Arity| Predicates], Object, Data0, Data) :-
functor(Fact, Functor, Arity),
findall(Fact, Object::Fact, Data1, Data0),
object_data(Predicates, Object, Data1, Data).
restore(File) :-
open(File, read, Stream),
read_term(Stream, Term, []),
restore_object(Term, _, Stream),
close(Stream).
restore_object(end_of_file, _, _).
restore_object(protocol(Protocol), Protocol, Stream) :-
read_term(Stream, Term, []),
restore_object(Term, Protocol, Stream).
restore_object(data(Data), Protocol, Stream) :-
create_object(_, [implements(Protocol)], [], Data),
read_term(Stream, Term, []),
restore_object(Term, Protocol, Stream).
:- end_object.
Это только отправная точка, однако. Его можно улучшить несколькими способами, но в основном это требует более подробной информации о конкретном сценарии сериализации.
Обновить
Добавил serialization
пример git-версии Logtalk на основе приведенного выше кода: https://github.com/LogtalkDotOrg/logtalk3/tree/master/examples/serialization