2015-12-04 6 views
1

У меня есть база знаний в файле Prolog (.pl) с использованием SWI-Prolog.Подсчитать факты в Прологе

reserve(bus(2389),place(4),datetravel([12,2,1999]), 
     info([88032454321,robert,downe])). 
reserve(bus(2389),place(33),datetravel([12,2,1999]), 
     info([88032454321,alberto,perez])). 
reserve(bus(2389),place(16),datetravel([12,2,1999]), 
     info([88032454321,angel,clark])). 
reserve(bus(4566),place(17),datetravel([22,3,2005]), 
     info([88032454321,don,self])). 
reserve(bus(2389),place(22),datetravel([12,2,1999]), 
     info([88032454321,singmud,dante])). 

Я реализовал правило, которое вы дали мне несколько параметров, подсчитывают количество событий, которые соответствуют этим ограничениям, но не работает для меня, как я могу?

Правило

test(N,D,M,Y,P):- 
    reserve(bus(N),place(4),datetravel([D,M,Y]), 
      info([88032454321,robert,downe])), 
    test(N,D,M,Y,P+1). 

Вопрос

?- test(2389,12,2,1999,P). 

Учитывая мой вопрос правило должен возвращать число 4.

+0

Вы не можете передать 'P + 1' и ожидать, что Prolog проверит выражение. Это не работает. он буквально передаст термин «+» (P, 1) 'в предикат. И у вас нет базового аргумента для' test', который обрабатывает тривиальный случай. С одним рекурсивным предикатом, когда вы ожидаете, что это закончится? И затем при каждом вызове 'test', Prolog будет придерживаться того же факта в соответствии с вашим правилом (поскольку новый запрос предиката начинается в начале для сопоставления фактов/правил по запросу), поэтому они не будут правильно подсчитывать их – lurker

+0

Простейшим способом подсчета будет использование 'findall', а затем длина результата:' findall (_, reserve (bus (_), place (4), datetravel ([_, _, _]), info ([88032454321, robert, downe])), L), length (L, N) .', а затем 'N' - счет. – lurker

+0

Я полностью понимаю, что я должен остановить случай, рекурсия такова. Я не люблю использовать предопределенную функцию findAll, я делаю это сам. Я искал реализацию findall в сети, но не могу ее найти, никаких идей? Я делаю это сам, но не начинаю. – user1813375

ответ

1

Посмотрите на библиотеку (aggregate).

Это мощный и заслуживающий изучения.

:- use_module(library(aggregate)). % optional, this library is autoloaded 
test(N,D,M,Y,P):- 
     aggregate_all(count, reserve(bus(N),place(4),datetravel([D,M,Y]),info([88032454321,robert,downe])), P). 

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

+0

Я не могу использовать (заполнить все), я реализую себя, любые идеи? – user1813375

1

Вот пример того, как вы могли рассчитывать факты, предполагая наличие уникального ключа. Этот пример просто имеет простой факт: foo/1 с одним аргументом, который является уникальным ключом. У меня здесь простая структура. Я оставлю это как упражнение, чтобы заставить его работать для вашего дела, что очень просто.

Кроме того, учитывая, что вы хотите написать код из более основополагающих принципов, я также отправлю письмо member/2 в качестве упражнения.

Вот как это называется. Вы можете жестко закодировать свой факт в count/2,4, если хотите. Здесь вы просто замените call(Thing, X) на foo(X) и полностью избавитесь от аргумента Thing. Но в этом случае, я решил сделать тот факт, функтор аргумента:

| ?- count(foo, N). 

N = 3 

yes 
| ?- 

На самом деле, count может предоставить весь перечень оцениваемых фактов, если вы хотите. Вы просто включили бы его в качестве дополнительного аргумента аккумулятора. Он уже собран в Seen.

+0

I модифицировано мой оценка это. 'Тест (N, D, M, Y, Р): - резерв (шина (N), место (4), datetravel ([D, M, Y]), информация ([88032454321, роберт, Downe])), add_list (P, L1, L2), len (L2, R). Я думаю, что это не сработает, но я не хочу усложнять даже такое решение, как ваше, как я могу следовать? – user1813375

+0

@ user1813375 У вас возникли проблемы с решением моего решения проблемы? Это должно быть прямо. Проблема с вашим предложением состоит в том, что 'add_list' имеет одноэлементную переменную' L1' (больше нигде не появляется), и она не сможет постоянно обновлять 'L2'. Как только переменная создается в предикате, она не может быть изменена, кроме как с помощью обратного отслеживания. – lurker

+0

@ user1813375, как я предложил в своем комментарии к вашему оригинальному сообщению, вы можете найти исходный код 'findall/3' для других идей. 'findall/3' использует' assertz' и 'retract' для выполнения того, что он делает. – lurker

Смежные вопросы