2
votes

I seem to be having an issue with the unification of facts in Prolog, but can't confirm it. Everything looks like it should work, and I've looked up examples of solved logic puzzles using Prolog to no real effect, given the relative rarity of Prolog.

This is an extra credit assignment, so I'm unsure if it's valid, but I'm genuinely stumped on how to proceed from here

% Names
name(teo).
name(mira).
name(bruno).
name(igor).

%Food
food(sandwich).
food(pie).
food(hamburger).
food(pizza).

%Hobby
hobby(crosswords).
hobby(writing).
hobby(reading).
hobby(photography).

%Shirt Colour
shirt(white).
shirt(yellow).
shirt(blue).
shirt(red).

%Other
girl(mira).

student((Name, Food, Hobby, Shirt)) :-
    name(Name), food(Food), hobby(Hobby), shirt(Shirt).

solution(L):-
    length(L,4),
    L= [student(teo, sandwich,_,_),_,_,_],
    member(student(mira, pite, crosswords,_),L),
    member(student(girl(GirlName),_,_,white),L),
    member(student(bruno,_,_,yellow),L),
    member(student(_,hamburger,writing,_),
    L= [_, student(_,pie,_,_),_,_],
    next(student(_,pie,_,_), student(teo,_,_,_), L),
    next(student(bruno,_,_,_), student(_,pizza,_,_), L),
    next(student(_,_,_,white), student(_,pizza,_,_), L),
    member(student(igor,_,reading,_),L),
    next(student(_,_,_,blue), student(girl(GirlName),_,_,_), L).

next(A, B, Ls) :- append(_, [A,B|_], Ls).
next(A, B, Ls) :- append(_, [B,A|_], Ls).

The issue is that it won't treat solution(L) as if it's a predicate or a rule, simply a block of text, so I can't even test if it's correct or not. I am most interested in why it won't even function.

1
What purpose is the predicate student((Name, Food, Hobby, Shirt)) :- name(Name), food(Food), hobby(Hobby), shirt(Shirt). supposed to provide? Your usage of student/4 everyone else in the program is simply as a data structure term. In addition, none of the smaller facts are exercised, either. If you say, for example member(student(girl(GirlName),_,_,white),L), Prolog does not query girl(GirlName) in this context to determine what values of GirlName make it true. It is simply a term in this context, not a query. - lurker
That makes sense. Does that mean I can simply input the facts into solution? Like member([mira, pite, crosswords,_], L)? - Riste Dimitrov
If you're consistent, you can do that. In other words, if you establish a convention that you are working with a list where the first element is the name, second is food, etc, then it works. There is nothing wrong with using the terms such as [name(mira), food(pite), ...], again as long as you're consistent. It's just that your code currently doesn't make use of the facts you have asserted that indicate what foods are valid foods, etc. If you want to make use of those facts, somewhere in your code you'd want something like, name(Name) ... then [Name, ...]. - lurker
Here's another example. Let's say we take your facts which describe valid foods, names, hobbies, and shirts. You could generate a list of valid sets using: findall( [Name, Food, Hobby, Shirt], (name(Name), food(Food), hobby(Hobby), shirt(Shirt)), AllPossibleCombinations). Try that at a Prolog prompt and see what it looks like. It's not clear from your question what problem solution is solving, so I can't offer any hints in that regard. - lurker
When you say The issue is that it won't treat solution(L) as if it's a predicate or a rule, simply a block of text, I don't understand. You do have a syntax error here: member(student(_,hamburger,writing,_), but outside of that, it looks like a perfectly well-formed Prolog rule/predicate. - lurker

1 Answers

3
votes

At first, I thought this girl/1 is the culprit as many have remarked. But even when removing all such occurrences your definition still fails (and after fixing that syntax error). Here is the responsible part that still fails for solution(L):

:- op(950, fy, *).
*(_).

solution(L) :-
   * length(L,4),
   L= [student(_/*teo*/, sandwich,_,_),_,_,_],
   member(student(_/*mira*/, pite, _/*crosswords*/,_),L),
   * member(student(girl(GirlName),_,_,white),L),
   * member(student(bruno,_,_,yellow),L),
   member(student(_,hamburger,_/*writing*/,_),L),
   L= [_, student(_,pie,_,_)|_/*[_,_]*/],
   * next(student(_,pie,_,_), student(teo,_,_,_), L),
   next(_/*student(bruno,_,_,_)*/, student(_,pizza,_,_), L),
   * next(student(_,_,_,white), student(_,pizza,_,_), L),
   * member(student(igor,_,reading,_),L),
   * next(student(_,_,_,blue), student(girl(GirlName),_,_,_), L).

next(A, B, Ls) :- append(_, [A,B|_], Ls).
next(A, B, Ls) :- append(_, [B,A|_], Ls).

All the names are irrelevant, just as their hobbies. What really matters is the food!

You have only four places, but a total of five foods (sandwich, pie, pite, hamburger, pizza) - give me just one of them!

That's the nice thing in Prolog: You can do such generalizations to get a clean diagnosis.