Циркулярный буфер в Turbo Prolog 2.0
Мне нужно написать что-то вроде кругового буфера в TurboProlog 2.0 для расчета среднего. Я не знаю, какие предикаты мне нужно написать, и понятия не имею, как их связать.
2 ответа
Я не уверен, какую функциональность "кольцевого буфера" нужно реализовать для вашего приложения. В общем случае "буфер" - это хранилище многократного использования, часто связанное с процессами ввода-вывода, которые обрабатывают асинхронную связь (отсюда необходимость в буфере, который позволяет одному процессу опережать другой). "Круговой буфер" обозначает способ управления доступным хранилищем с помощью указателей (как на начало, так и на конец действительных / необработанных данных), которые охватывают (линейную) непрерывную область. Это имеет преимущество перед сохранением очереди FIFO с фиксированным местоположением для начала допустимых данных, потому что не требуется "перетасовка" необработанных элементов.
В общем контексте стандартного Пролога, где перезапись областей памяти напрямую не поддерживается, это преимущество не имеет смысла. Даже в Turbo Prolog необходимо точно спросить, чего вы хотите достичь, чтобы можно было умело использовать доступные расширенные / нестандартные функции.
Вот несколько идей:
Turbo Prolog поддерживает списки, которые в некоторых отношениях являются более ограничительными и, возможно, другими способами более сложными, чем соответствующие списки стандартных Prolog. Одним из ограничений является то, что в Turbo Prolog все элементы списка должны принадлежать одному и тому же "домену", понятие, чуждое слабо типизированному символу стандартного Prolog. Также домены могут быть обозначены как "эталонные" домены в Turbo Prolog, уровне косвенности, который позволяет передавать частично связанные составные термины между подцелями. Не вдаваясь в подробности, одним смыслом "кругового буфера" может быть "список" (сформированный из ссылочной области), который оборачивается вокруг себя (циклическая ссылка). Такой термин может быть создан во многих других Прологах, с той разницей, что это не правильный список. Несмотря на то, что такой термин может быть круговым, он не будет представлять собой большую часть буфера (после его создания), поскольку элементы в списке не могут быть переписаны.
Turbo Prolog поддерживает динамическое утверждение и отвод фактов с помощью метапредикатов, таких как asserta/1 и assertz/1, которые позволяют последовательно позиционировать новые факты в начале или конце этих существующих фактов для того же предиката (а также, если необходимо, в пределах указанного именованного "модуль" или база фактов для использования терминологии Turbo Prolog). Если вашей целью является простое управление элементами в очереди FIFO, то это, скорее всего, тот подход, который вам нужен (по крайней мере, для начальной реализации), с элементами, инкапсулированными как факты.
Turbo Prolog также поддерживает "внешние" базы фактов с некоторыми дополнительными функциями, внешними в том смысле, что они сохраняются (либо в памяти, либо на диске) таким образом, чтобы обеспечить постоянство и расширение пространства сверх того, что выделено для внутренних баз фактов. Учитывая скромные фиксированные размеры, обычно связанные с циклическими буферами (поскольку они предназначены для повторного использования, а переполнение обычно решается путем блокирования процесса ввода до тех пор, пока процесс вывода не сможет наверстать упущенное), внешние базы фактов, по-видимому, не предлагают много представляет интерес, хотя, возможно, способность сохранять "буферы" может представлять интерес для длительных процессов.
Надеемся, что эти предложения позволят получить некоторые разъяснения о том, что действительно нужно сделать здесь.
После долгих раздумий была написана следующая программа
% Consumer predicate. If buffer is empty, nothing to take, need to wait for producer predicate.
consumer(BufferBefore, [], _) :-
length(BufferBefore, BuffSize),
BuffSize = 0,
write("Buffer is empty. Waiting for producer"), nl, !, fail.
% If the buffer is not empty, returns first element and removes them from the buffer
consumer(BufferBefore, BufferAfter, Result) :-
car(BufferBefore, Result),
deletefirst(BufferBefore, BufferAfter).
% Producer predicate. If data and buffer is empty, nothing taken from the data to put in buffer.
producer([], [], [], [], _) :- write("End of data!."), !, fail.
% Else if buffer is not empty, add first elem from data (and removes them from here) to last position in buffer.
producer(DataBefore, BufferBefore, DataAfter, BufferAfter, Size) :-
length(BufferBefore, BuffSize), BuffSize < Size, !,
car(DataBefore, Elem),
addlast(Elem, BufferBefore, BufferAfter),
deletefirst(DataBefore, DataAfter).
Несколько примеров бега
consumer([1,2,3,4,5], BufferAfter, Result)
возвращается
BufferAfter = [2,3,4,5], Result = 1.
А также
producer([1,2,3,4,5,6],[7,8,9],DataAfter, BufferAfter, %">3 here"%)
возвращается
DataAfrer = [2,3,4,5,6], BufferAfter = [7,8,9,1].
Теперь, чтобы продемонстрировать какой-либо расчет, нам нужно написать программу, которая будет запускать "потребитель", пока буфер не будет пустым. И "потребитель" будет запускать "производитель", когда буфер пуст. И остановите процесс, когда данные и буфер станут пустыми. Надеюсь, будет полезно для всех.