Ordering Facts In Prolog

Cetra

n00b
Joined
Apr 23, 2009
Messages
32
I have an order of facts, below is an example:

nutrition(cheeseburger, 300, 12, 33, 15).
nutrition(hamburger, 250, 9, 31, 12).
nutrition(chickenPieces, 270, 16, 19, 14).

In these examples the first atom is a food, the second is the number of calories, third is the fat, fourth is the number of carbohydrates, and fifth is the amount of protein.

What I'm trying to do is output these items based on the amount of fat in each. My initial idea is to use an iterator and go from 0 to 100 fat, but seeing as iteration isn't a possibility in Prolog, I can't figure out a good approach to take. If ordered correctly the output would be:

hamburger
250
9
31
12
cheeseburger
300
12
33
15
...

My other idea is to put all of the fat amounts into a list, but when I recurse the order starts over again. That idea is implemented below:

sort_menu(M, TC, F, C, P, Z) :- nutrition(M, TC, F, C, P),
sort_menu(M, TC, F, C, P, [F|Z]).
 
... seeing as iteration isn't a possibility in Prolog ...
Just because you don't have loop constructs, doesn't mean you can't iterate. Anything expressible as a loop can be defined recursively.

My other idea is to put all of the fat amounts into a list, but when I recurse the order starts over again. That idea is implemented below:

sort_menu(M, TC, F, C, P, Z) :- nutrition(M, TC, F, C, P),
sort_menu(M, TC, F, C, P, [F|Z]).
The nutrition/5 call is always going to match the first fact in the database. That is, unless the next predicate fails and the solver backtracks to find a new match. You want to follow nutrition/5 with something which will fail on any case you've already included.

A couple more things:
- Why all the arguments to sort_menu/6? All the information it needs is in the database. It should only need a single argument, for the resulting list.
- Take a closer look at where you're putting that 'F'...
 
Listening to what you said I came up with:
sort_menu(X, [F,H|T]) :- nutrition(M, TC, F, C, P), F\= X.

The F\=X becomes false, because I'm comparing a number to an atom that has no value. This restarts nutrition and gives me all of the facts. The problem is where to put F so that all the Fs will be put into the second argument of sort_menu when the recursion ends.
 
You've kind of gone for the other extreme here. In your first version, nutrition(M, TC, F, C, P) is unconditionally true; in this case you've made it unconditionally false. What you want is something which fails only when nutrition/5 returns something which is already in your list - you only want it to backtrack until it finds something new.

You still need a recursive call in there... where else is T going to come from?
 
I see what your saying but I can't really test an uninitialized variable and if I do initialize a variable then that happens every time I recurse.
 
Wow, I now officially hate my professor for being so tricky. Turns out that setof() pretty much does it for me. Here is the completed work.

sort_menu(A, B, Out) :- setof(A,B ^ nutrition(A,_,B,_,_), Out).

Input: sort_menu(A,B,C).

Output:
C = [hamburger]
C = [cheeseburger]
C = [chickenPieces]

It is all in the correct order, and my professor didn't specify having to print out the amount of fat so I think I'm alright.
 
Back
Top