1
votes

I have a base of knowledge in a Prolog file (.pl) using 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])).

I implemented a rule that ye gave me several parameters count the number of events that comply with these restrictions, but does not work for me, as I can?

Rule

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).

Question

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

Given my question the rule should return the number 4.

2
You can't pass P+1 and expect Prolog to evaluate the expression. It doesn't work that way. it will literally pass the term, '+'(P,1) to the predicate.And you don't have a base case for test that handles the trivial case. With just one recursive predicate, when would you expect it to end? And then with each call to test, Prolog will keep matching the same fact to the rule you have (since a new predicate call starts at the beginning for matching facts/rules on a query), so that won't properly count them - lurker
The simplest way to count them would be to use findall then take the length of the result: findall( _, reserve(bus(_), place(4), datetravel([_,_,_]), info([88032454321, robert,downe])), L), length(L, N). and then N is the count. - lurker
I fully understand that I have to stop the case, recursion is so. I do not like to use a predefined function as findAll, I make it myself. I searched the implementation of findall on the network but can not find it, any ideas? I do it myself but not to start. - user1813375
not really something as specific interests me more power to implement something myself, but where to start? It occurs to me to save each value of P in a list and then see its length, would be fine as well? - user1813375
Googling "SWI prolog source" gives yields the link to the SWI "build from source" page. To get the source for findall/3 from SWI's implementation, you can download the SWI source. - lurker

2 Answers

2
votes

Take a look at library(aggregate).

It's powerful and worth to study.

:- 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 is just a placeholder for a query... actually, your data model isn't easy to interface. Since Prolog data model is relational, you should try to apply techniques similar to those employed designing SQL databases.

1
votes

Here's an example of how you could count facts assuming there's a unique key. This example just has a simple fact, foo/1 with one argument, which is the unique key. What I have here is a simple framework. I'll leave it as an exercise to make it work for your case, which is very straightforward.

Also, given that you want to write the code from more fundamental principles, I'll leave writing member/2 as an exercise as well.

foo(a).
foo(b).
foo(c).

count(Thing, N) :-
    count(Thing, [], 0, N).

count(Thing, Seen, Acc, N) :-
    call(Thing, X),
    (   member(X, Seen)
    ->  fail
    ;   !,
        Acc1 is Acc + 1,
        count(Thing, [X|Seen], Acc1, N)
    ).
count(_, _, N, N).

Here's how it's called. You can hard-code your fact functor in count/2,4 if you wish. Here, you'd just replace call(Thing, X) with foo(X) and get rid of the Thing argument altogether. But in this case, I decided to make the fact functor an argument:

| ?- count(foo, N).

N = 3

yes
| ?-

Actually, count can provide the entire list of evaluated facts if you wish. You would just include it as an extra accumulator argument. It's already collected in Seen.