Reputation: 1827
So I've got facts that are written like this document(Title,Topic)
. I want to make a rule where with two arguments.The first one is Keys which is a list of keywords and the second one is the document.
I want to get as a result the titles of the documents which cointain the keywords I've given.
This is what I wrote till now:
isInDoc([],'no'). %Recursion stops here. Don't know what to put as 2nd argument
isInDoc([H|T],document(Title,_)) :-
sub_string(case_insensitive,H,document(Title,_)),
isInDoc(T,document(Title,_)).
What I've thought is that I read the head of the list of keywords and see if it is a substring of the title of the document. When I type document(Title,_)
in SWI-Prolog I get the titles of the documents. I can't think of any other way to get access to the title of the document. If I do a question I get this error ERROR: table: sub_string/3: Type error:'text' expected, found document(_G6503,_G6504)
.
Isn't document(Title,_)
of type text?
Upvotes: 1
Views: 168
Reputation: 60034
in SWI-Prolog, sub_string/5 has been introduced recently, but works only on strings. The correct predicate to use is sub_atom/5 (it is also ISO standard):
isInDoc(Tokens, document(Title, _)) :-
member(Token, Tokens),
sub_atom(Title, _,_,_, Token).
4 ?- document(T,_), isInDoc([and], document(T,_)).
T = 'Rules and Uncertainty' ;
false.
5 ?- document(T,_), isInDoc([and, certa], document(T,_)).
T = 'Rules and Uncertainty' ;
T = 'Rules and Uncertainty' ;
false.
I use member/2 to 'try' all tokens, instead of writing a recursive rule. Btw, since you expect that isInDoc/2 will fail when any of the tokens cannot be found, you can drop altogether the base case (but since you used no
, that will never match document(_, _), the effect is the same).
edit Maybe the snippet can be made more useful separating the matching of atoms from the document:
isInDoc(Tokens, document(Title, _)) :- contains(Tokens, Title).
contains(Tokens, Atom) :-
member(Token, Tokens),
sub_atom(Atom, _,_,_, Token).
Upvotes: 3