I am trying to build a simple predicate which get as inputs two lists and the results is a third one consisting of the intersection of the first two. I have decided to do using logical statement. I am pretty sure my logic is correct but my predicate is not working. Any ideas?:
element(X,[H|T]) :- X=H ; element(X,T). intersection(L1,L2,R) :- not(( element(A,L1), not(element(A,L2)) )), not(( element(A,L1), not(element(A,R)) )).
Please do not post alternative methods I am wondering why this one returns FALSE every time.
2 Answers
Answers 1
The problem is that not/1
merely negates the outcome of your element/2
. It doesn't cause element/2
to backtrack to find other instantiations for which the enclosing not/1
will be true.
Consider the following program.
a(1). a(2). b(1). b(2). b(3).
And the following queries:
b(X), not(a(X))
.not(a(X)), b(X)
.
The first one yields X = 3
while the second one yields false
. That is because the first query first instantiates X
with 1, then with 2, then with 3, until finally not(a(X))
succeeds.
The second query first instantiates X
with 1, a(1)
succeeds, so not(a(1))
fails. There is no backtracking done!
Answers 2
Your definition is correct. For the ground case. What is a bit unusual is that the intersection is the first and not the last argument.
It is a bit too general, though - like many Prolog predicates (think of append([], non_list, non_list)
. Apart from lists, your definition admits also terms that are neither lists nor partial lists:
?- intersection(non_list,[1,2|non_list],[3,4|non_list])
To make it really useful safe, use it like so:
?- when(ground(intersection(I, A, B), intersection(I, A, B)).
or so:
?- ( ground(intersection(I, A, B)) -> intersection(I, A, B) ; throw(error(instantiation_error, interaction(I, A, B))) ).
As a minor remark, rather write (\+)/1
in place of not/1
.
0 comments:
Post a Comment