Циркулярный буфер в Turbo Prolog 2.0

Мне нужно написать что-то вроде кругового буфера в TurboProlog 2.0 для расчета среднего. Я не знаю, какие предикаты мне нужно написать, и понятия не имею, как их связать.

2 ответа

Решение

Я не уверен, какую функциональность "кольцевого буфера" нужно реализовать для вашего приложения. В общем случае "буфер" - это хранилище многократного использования, часто связанное с процессами ввода-вывода, которые обрабатывают асинхронную связь (отсюда необходимость в буфере, который позволяет одному процессу опережать другой). "Круговой буфер" обозначает способ управления доступным хранилищем с помощью указателей (как на начало, так и на конец действительных / необработанных данных), которые охватывают (линейную) непрерывную область. Это имеет преимущество перед сохранением очереди FIFO с фиксированным местоположением для начала допустимых данных, потому что не требуется "перетасовка" необработанных элементов.

В общем контексте стандартного Пролога, где перезапись областей памяти напрямую не поддерживается, это преимущество не имеет смысла. Даже в Turbo Prolog необходимо точно спросить, чего вы хотите достичь, чтобы можно было умело использовать доступные расширенные / нестандартные функции.

Вот несколько идей:

  1. Turbo Prolog поддерживает списки, которые в некоторых отношениях являются более ограничительными и, возможно, другими способами более сложными, чем соответствующие списки стандартных Prolog. Одним из ограничений является то, что в Turbo Prolog все элементы списка должны принадлежать одному и тому же "домену", понятие, чуждое слабо типизированному символу стандартного Prolog. Также домены могут быть обозначены как "эталонные" домены в Turbo Prolog, уровне косвенности, который позволяет передавать частично связанные составные термины между подцелями. Не вдаваясь в подробности, одним смыслом "кругового буфера" может быть "список" (сформированный из ссылочной области), который оборачивается вокруг себя (циклическая ссылка). Такой термин может быть создан во многих других Прологах, с той разницей, что это не правильный список. Несмотря на то, что такой термин может быть круговым, он не будет представлять собой большую часть буфера (после его создания), поскольку элементы в списке не могут быть переписаны.

  2. Turbo Prolog поддерживает динамическое утверждение и отвод фактов с помощью метапредикатов, таких как asserta/1 и assertz/1, которые позволяют последовательно позиционировать новые факты в начале или конце этих существующих фактов для того же предиката (а также, если необходимо, в пределах указанного именованного "модуль" или база фактов для использования терминологии Turbo Prolog). Если вашей целью является простое управление элементами в очереди FIFO, то это, скорее всего, тот подход, который вам нужен (по крайней мере, для начальной реализации), с элементами, инкапсулированными как факты.

  3. 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].

Теперь, чтобы продемонстрировать какой-либо расчет, нам нужно написать программу, которая будет запускать "потребитель", пока буфер не будет пустым. И "потребитель" будет запускать "производитель", когда буфер пуст. И остановите процесс, когда данные и буфер станут пустыми. Надеюсь, будет полезно для всех.

Другие вопросы по тегам