6

I'm new to prolog, and am experimenting with how to get it to stop querying after it finds one answer. I'm using this code:

member1(L,[L|_]).                    
member1(L,[_|RS]) :- member1(L,RS),!.      

The result is:

| ?- member1(3,[3,2,3]).

true ? a

yes

I'm lost as to how I could get Prolog to stop printing "true ?" and just print "yes" instead. I've tried using if/else construct and the format function but it still prints "true ?". Any ideas?

false
  • 10,264
  • 13
  • 101
  • 209
user3026297
  • 63
  • 1
  • 1
  • 3
  • You just want one answer? one `true` ? Τrue means that 3 *is* a member of the list [3,2,3]. The second true is that the query found it again in the list. ` member1(2,[3,2,3]).` would give you only one true. – Shevliaskovic Nov 24 '13 at 20:44
  • If you press enter after the first true (instead of `;`), it would stop backtracking – Shevliaskovic Nov 24 '13 at 20:48

2 Answers2

4

You're cutting the wrong place. Cut after the base condition, which says, "once the base is met, don't backtrack any more":

member1(L,[L|_]) :- !.                   
member1(L,[_|RS]) :- member1(L,RS).    

If-then does work for me, perhaps you implemented it different? (on swi-prolog)

member1(X,[Y|RS]) :-
    ( X = Y         -> true
    ; member1(X,RS) -> true
    ; false
    ) .

Swi also has the predicate once/1.

edited to account for the error pointed out by false.

Shon
  • 3,989
  • 1
  • 22
  • 35
  • @false Ah! I had overlooked obvious situation in which the very first element matches. Fixed now. Thanks for pointing that out. – Shon Nov 27 '13 at 00:52
2

From the output you show, I assume you are using GNU Prolog. But, first just an important remark:

The cut you placed does not cut as you intend it! In fact, it does not even prevent that there is a single answer. Here is evidence for that:

| ?- member1(X,[1,2,3]).

X = 1 ? ;

X = 2

yes

So you still have two answers. As a rule of thumb: a cut after a recursive goal often does some unexpected things.

If you insist to have exactly the first answer, simply say once(member(X,[1,2,3])). The once/1 is effectively a cut, too, but quite in disguise. It is tamed to do exactly one thing. Yes, you can place also cuts into recursive rules, but for a beginner, better leave that to a later lesson.

Behind all this there is another point, which is less visible: The toplevel shell of GNU Prolog will ask you for further solutions if it sees an open alternative (jargon: choicepoint). So when GNU asks you for more, it knows that some part has yet to be explored, but there is no guarantee, that there is actually another answer:

?- member(1-X,[1-a,2-b,3-c]). 

X = a ? ;

no

Here, the toplevel sees an open choicepoint and thus asks if you want to explore the query any further. Alas, this search is in vein...

false
  • 10,264
  • 13
  • 101
  • 209