1

We have this assignment for our Prolog course. After two months of one hour per week of Prolog, it is still an enigma to me, my thinking seems unable to adapt from procedural languages - yet.

There is a knowledge base containing predicates/functors with the same name and arities 1, 2 and 3. The call form should be

search(functor_name, argument, S).

The answers should find all occurrences with this functor name and argument, regardless of arity. The answers should be of the form:

S = functor_name(argument);
S = functor_name(argument,_);
S = functor_name(_,argument);
S = functor_name(argument,_,_);
S = functor_name(_,argument,_);
S = functor_name(_,_,argument);
false.

I have found out that I could use call to test if the entry in the knowledge base exists.

But call does not seem to work with a variable for the functor name. I am totally baffled, no idea how to use a variable for a functor name.

UPDATE:

My question has been partly answered. My new code gives me true and false for arities 1, 2 and 3 (see below).

search(Person,Predicate) :-
   ID = Person, Key = Predicate, current_functor(Key,1),
   call(Key,ID)
 ; ID = Person, Key = Predicate, current_functor(Key,2),
   (call(Key,ID,_);call(Key,_,ID))
 ; ID = Person, Key = Predicate, current_functor(Key,3),
   (call(Key,ID,_,_);call(Key,_,ID,_);call(Key,_,_,ID)).

UPDATE2:

Another partial answer has come in. That one gives me S as a list of terms, but the "other" arguments are placeholders:

search2(Predicate, Arg, S) :-
   ( Arity = 2 ; Arity = 3 ; Arity = 4 ),
   functor(S, Predicate, Arity),
   S =.. [_,Predicate|Args],
   member(Arg, Args).

The result is quite nice. Still missing: the Predicate should not be inside the brackets and the other arguments should be taken literally from the knowledge base, not written as placeholders. The current result looks like this:

 ?- search2(parent,lars,S).
S = parent(parent, lars) ;
S = parent(parent, lars, _G1575) ;
S = parent(parent, _G1574, lars) ;
S = parent(parent, lars, _G1575, _G1576) ;
S = parent(parent, _G1574, lars, _G1576) ;
S = parent(parent, _G1574, _G1575, lars).

I am giving up with this question, because the question was posed in the wrong way from the beginning. I should have asked more specifically - which I could not, because I am still no good in Prolog.

@false helped me most. I am accepting his answer.

false
  • 10,264
  • 13
  • 101
  • 209
AOphagen
  • 308
  • 2
  • 18
  • -1 for adding an additional, unrelated question after receiving answers. There are lots of SO questions about gathering results already. – Fred Foo Jun 10 '14 at 10:13
  • So, if I do not find the answer, would I rather write a new question? – AOphagen Jun 10 '14 at 10:16
  • If your original question is answered, you should accept the most suitable answer, and then post a new question if you have a new question. You should not use a single SO question as a stream of follow-up questions before you consider it acceptable. It's not a forum thread. It's supposed to be (1) ask a specific technical quesiton, (2) get specific answer(s). A new question needs a separate post. – lurker Jun 10 '14 at 10:57
  • OK, my question was not good - too complicated. We are not even coming close to what I wanted. I have two partial answers that need to be combined, now. No matter which I accept, I will be mean to the other person. :( – AOphagen Jun 10 '14 at 11:09
  • 1
    If SO allows you to upvote, you could upvote each helpful answer even if you can't accept one as complete. – lurker Jun 10 '14 at 11:15

2 Answers2

4

There are two approaches here, one "traditional" (1970s) that implements literally what you want:

search(F, Arg, S) :-
   ( N = 1 ; N = 2 ; N = 3 ), % more compactly: between(1,3, N)
   functor(S, F, N),
   S =.. [_|Args],            % more compactly: between(1,N, I), arg(I,S,Arg)
   member(Arg, Args).

The other reconsiders the explicit construction of the goal. Actually, if you have a functor F, and arguments A1, A2, A3 you can immediately write the goal call(F, A1, A2, A3) without any use of functor/3 or (=..)/2.

There are many advantages of using call(F, A1, A2, A3) in place of Goal =.. [F, A1, A2, A3], call(Goal): In many situations it is cleaner, faster, and much easier to typecheck. Further, when using a module system, the handling of potential module qualifications for F will work seamlessly. Whereas (=..)/2 will have to handle all ugly details explicitly, that is more code, more errors.

search(F,A,call(F,A)).
search(F,A,call(F,A,_)).
search(F,A,call(F,_,A)).
search(F,A,call(F,A,_,_)).
search(F,A,call(F,_,A,_)).
search(F,A,call(F,_,_,A)).

If you want to shorten this, then rather construct call/N dynamically:

search(F, Arg, S) :-
   ( N = 2 ; N = 3 ; N = 4 ),
   functor(S, call, N),
   S =.. [_,F|Args],
   member(Arg, Args).

Note that call needs an extra argument for the functor F!

false
  • 10,264
  • 13
  • 101
  • 209
  • The last example gives me a list of format "S = call(parent, ...up to three further things, one of which is the parameter)". The other things in the output are the placeholders _Gxxxx. What I want is each entry in the knowledge base that contains the predicate with irrelevant arity and the parameter for one of its arguments. Then, a list of each entry with the other arguments, like 'jon', 'margret', whatever. All other colleagues have given up, cursing Prolog. Problem is, I can hardly read the code examples. Whenever I change anything to try to make it work like I want, compiling just fails. – AOphagen Jun 10 '14 at 10:44
  • @AOphagen: The example is not necessarily the best to start with. But – false Jun 10 '14 at 10:48
  • @AOphagen: You probably wanted `search(F, Arg) :- current_predicate(F/N), functor(Goal, F, N), between(1,N, I), arg(I,Goal,Arg), call(Goal).` But it is not very well stated. – false Jun 10 '14 at 10:51
  • Uff, thanks for you continuing help. Yes, that looks as if it would take a while to run. Unification is something I definitely do not understand. I will play a bit with that and see what will happen. BTW, the teacher will retire any year now, he was probably aiming for something you might find legacy methods. – AOphagen Jun 10 '14 at 11:02
3

You can use the "univ" operator, =.., to construct a goal dynamically:

?- F=member, X=1, L=[1,2,3], Goal =.. [F, X, L], call(Goal).
F = member,
X = 1,
L = [1, 2, 3],
Goal = member(1, [1, 2, 3]) .
Fred Foo
  • 355,277
  • 75
  • 744
  • 836
  • Replace `Goal =.. [F, X, L], call(Goal)` by `call(F, X, L)` – false Jun 10 '14 at 09:15
  • Yes, I know. My problem is that I do not understand how to use either. But there is some progress. 23 ?- F=parent, X=hans, call(F,X). F = parent, X = hans. happy. (kind of) – AOphagen Jun 10 '14 at 09:36
  • As your list of arguments is not fixed, you might want to use `apply/2` instead of `call/2`. – Tudor Berariu Jun 10 '14 at 09:42
  • 3
    @TudorBerariu: `apply/2` is definitely the worst: It does not typecheck, and is inherently inefficient, and is no longer supported by many system. – false Jun 10 '14 at 09:50