3

i'm programming a family in prolog and i'm having trouble with the nephew implementation. When I ask if erick is the nephew of Alberto it returns true, when it should return false because Alberto is the father of erick, however, it does works for all the other cases that should be true. If someone could help me I would be very grateful. My code:

man(beto).
man(fransisco).
man(alberto).
man(jaime).
man(manolo).
man(nolo).
man(lito).
man(manuel).
man(erick).
man(jesu).
man(jesus).
woman(emi).
woman(harumi).
woman(haru).
woman(yuneisi).
woman(yasmeli).
woman(mioara).
woman(elia).
woman(iza).
woman(alice).
woman(ofelia).
woman(arlet).
parent(manuel, alberto).
parent(ofelia, alberto).
parent(manuel, jaime).
parent(ofelia, jaime).
parent(manuel, manolo).
parent(ofelia, manolo).
parent(alberto, erick).
parent(alberto, beto).
parent(alberto, fransisco).
parent(emi, erick).
parent(emi, beto).
parent(manolo, nolo).
parent(manolo, arlet).
parent(nolo, lito).
parent(iza, lito).
parent(mioara, yuneisi).
parent(mioara, yasmeli).
parent(jaime, yuneisi).
parent(jaime, yasmeli).
parent(jesus_padre, jesu)
parent(jesus_padre, alice).
parent(jesus_padre, haru).
parent(harumi, haru).
parent(harumi, jesu).
parent(harumi, alice).
father(X,Y) :- parent(X,Y), man(X).
mother(X,Y) :- parent(X,Y), woman(X).
brother(X,Y) :- man(X), parent(F, X), parent(F, Y).
sister(X,Y) :- woman(X), parent(P, X), parent(P, Y).
grandpa(X,Y) :- father(F,Y), father(X,F), man(X).
grandma(X,Y) :- father(F,Y), mother(X,F), woman(X).
son(X,Y) :- father(Y,X), man(X).
nephew(X,Y) :- father(F,X), brother(F,Y).
  • 1
    Your code should not work because you have a syntax error at the line "parent(jesus_padre, jesu)" , you forgot to put a dot at the end. It should work now and one more tip: Type in "guitracer " and then "tracer" if you have any faults you can see where it fails – Luai Ghunim Nov 04 '17 at 01:06

2 Answers2

5

Besides the missing dot after parent(jesus_padre, jesu) as pointed out by @LuaiGhunim there are a few other issues with your predicates. Your definition of brother/2 is too general. Nobody is his own brother but if you query your predicate you find several such instances:

?- brother(X,X).
X = beto ;
X = beto ;
X = fransisco ;
X = alberto ;
X = alberto ;
X = jaime ;
X = jaime ;
X = manolo ;
X = manolo ;
X = nolo ;
X = lito ;
X = lito ;
X = erick ;
X = erick ;
X = jesu ;
X = jesu ;
false.

You can easily remedy this by adding a goal dif/2:

brother(X,Y) :-
   dif(X,Y),
   man(X),
   parent(F, X),
   parent(F, Y).

Now the query above fails as it should:

?- brother(X,X).
false.

You'll still get a lot of pairs twice:

?- brother(X,Y).
X = beto,               % <- 1st occurrence
Y = erick ;             % <- 1st occurrence
X = beto,
Y = fransisco ;
X = beto,               % <- 2nd occurrence
Y = erick ;             % <- 2nd occurrence
.
.
.

The reason for that is that you can derive it via the mother or the father. In the above example (beto and erick) you'll get there via emi or alberto. These solutions might be redundant but they are correct. The same goes for your predicate sister/2:

?- sister(X,X).
X = haru ;
X = haru ;
X = yuneisi ;
X = yuneisi ;
X = yasmeli ;
X = yasmeli ;
X = alice ;
X = alice ;
X = arlet.

The remedy is the same as above:

sister(X,Y) :-
   dif(X,Y),
   woman(X),
   parent(P, X),
   parent(P, Y).

?- sister(X,X).
false.

?- sister(X,Y).
X = haru,
Y = jesu ;
X = haru,
Y = alice ;
X = haru,
Y = jesu ;
.
.
.

Your definition of grandma/2 and grandpa/2 on the other hand is too specific. To see this let's add the following facts to your code:

man(m1).
man(m2).

woman(w1).
woman(w2).
woman(w3).

parent(m1,w1).
parent(w1,w2).
parent(w2,w3).

Then the following queries should succeed but they fail instead:

?- grandpa(m1,w2).
false.

?- grandma(w1,w3).
false.

The reason for this is that the intermediate parent in your definition of grandpa/2 and grandma/2 is a father/2 where it should be a parent/2. Additionally the last goals (man(X) and woman(X)) are redundant since they are already covered by father/2 and mother/2 respectively. Instead, you could define the two predicates like so:

grandpa(X,Y) :-
   parent(F,Y),
   father(X,F).

grandma(X,Y) :-
   parent(F,Y),
   mother(X,F).

Now the above queries yield the desired result:

?- grandpa(m1,w2).
true.

?- grandma(w1,w3).
true.

Finally, a nephew according to the Cambridge Dictionary is a son of your sister or brother, or a son of the sister or brother of your husband or wife. Since you haven't got predicates for husbands and wives I'll stick with the a son of your sister or brother part. If you add facts for husbands and wives, you can add additional rules to cover the other part of the definition. You can write the first part of the definition in Prolog like so:

nephew(X,Y) :-
   man(X),
   dif(F,Y),
   parent(P,F),
   parent(P,Y),
   parent(F,X).

If you query this predicate there's no erick/alberto solution any more:

?- nephew(erick,X).
X = jaime ;
X = manolo ;
X = jaime ;
X = manolo ;
false.
tas
  • 7,772
  • 2
  • 11
  • 20
  • 1
    Maybe I'm old school, but I don't understand why to propose dif/2 when a standard builtin would work... What about users of simpler Prologs, willing to learn the basic ? – CapelliC Nov 04 '17 at 08:42
  • 3
    @CapelliC: I would argue that dif/2 is easier to use than the alternatives, especially for new users. Consider the following queries: `?- A\=B.` yields `false.`, while `?- dif(A,B).` yields `dif(A, B).`, that is, the constraint is propagated. Consequently `?- A\=B, A=a, B=b.` yields `false.` but `?- A=a, B=b, A\=B.` succeeds with `A = a,B = b.`. On the other hand `?- A=a, B=b, dif(A,B).` and `?- dif(A,B), A=a, B=b.` both yield `A = a,B = b.`. As a consequence it is necessary to make sure... – tas Nov 04 '17 at 11:45
  • 2
    @CapelliC: ...that a goal containing \=/2 is posted after both its arguments are ground, since even `?- A=a, A\=B, B=b.` yields `false.`. This can lead to errors that are quite hard to find for new users. I'm well aware that dif/2 is not available in all Prolog implementations but it is in many. And I'm certainly not against using standard built-ins, I just find dif/2 to be the easier/more elegant choice so I propose it :-) – tas Nov 04 '17 at 11:46
  • 1
    I agree about the elegance of dif/2, but *strongly* disagree about the argument of being easier for new users. IMHO a newbie *must* learn about the nuances implicit in goals orders, since - I feel - this the *essential* of Prolog as a programming language, its distinguishing feature. BTW I had some hard time modelling and (perhaps more importantly) debugging code that make use of delayed execution. – CapelliC Nov 04 '17 at 12:27
  • 4
    @CapelliC: I concur that learning about goal orderings is essential. But some aspects of it are easier to grasp than others. An aspect that I found intuitively easy to grasp is that some goals might narrow the search space more than others and that putting those goals first might result in faster predicates. However, knowing that goals are connected by conjunction and that conjunction is commutative, I found it quite counterintuitive that A & B & C might yield a different result than B & C & A. That's why I think dif/2 might be easier for beginners. – tas Nov 04 '17 at 15:07
  • Thanks alot to everyone helping. I'm new in prolog and really appreciate your help. – Erick Siordia Nov 04 '17 at 20:57
  • 2
    @tas: "result in faster predicates" - at least putting always terminating goals first will not deteriorate termination properties. That is, either they remain the same or get better. Speedwise, well it all depends – false Nov 05 '17 at 16:28
  • @false: We have no disagreement there. My previous comment was just an example what I personally found intuitively easy to grasp and I considered that specific aspect of goal ordering before I pondered termination properties. Concerning "Speedwise,...": I deliberately wrote "__might__ result in faster predicates" ;-) – tas Nov 05 '17 at 20:40
1

Prolog it's all about relations. Joins plays a fundamental role. So, often you can think in term of 'yields', or functions over the DB, and design/control the data access plan by means of joins (clauses, i.e. logical formulae) producing records - like SQL does. The procedural execution over the retrieved data is expressed in (almost) the same language: joins, giving us a taste of declarative programming. Anyway, here are the clauses provided by @tas in standard Prolog:

brother(X,Y) :-
   man(X),
   parent(F, X),
   parent(F, Y),
   X\=Y.

sister(X,Y) :-
   woman(X),
   parent(P, X),
   parent(P, Y),
   X\=Y.
CapelliC
  • 57,813
  • 4
  • 41
  • 80
  • 1
    The definition becomes incorrect, if you put `X\=Y` even one goal in front. If you use [`iso_dif(X,Y)`](https://stackoverflow.com/a/20238931) this cannot happen! It issues a clean error. So even in standard Prolog you can write correct and robust programs! – false Nov 05 '17 at 16:33