views:

92

answers:

3

Ok, so i have this

edu_less(hs,college).
edu_less(college,masters).
edu_less(masters,phd).

I need to write a function to tell if something is than the other. The predicate is

edu_le.

So if i put edu_le(hs,phd). it should return yes. I came up with this.

edu_le(A,B) :- A = B.
edu_le(A,B) :- edu_less(A,B).
edu_le(A,B) :- edu_less(A,C), edu_le(C,B).

I really don't want it to go through everything and return multiple answers.

Is it possible to only return yes or no if it finds that it is in fact less than or equal to the 2nd argument?

So basically if i use the example edu_le(hs,phd) again, then because hs is less than college, and college is than masters, and masters is less than phd, then hs must be less than phd and it would say yes.

Sorry, really new to prolog, still trying to get the hang of this.

+1  A: 

The most practical way to write predicates like that is to use the cut (!). The cut causes further clauses not to be considered when backtracking. You would write your predicate as following:

edu_le(A,B) :- A = B, !.
edu_le(A,B) :- edu_less(A,B), !.
edu_le(A,B) :- edu_less(A,C), edu_le(C,B).

The last clause does not need a cut because there are no further clauses to consider anyway. The cut is placed after any tests to determine whether the clause should succeed.

Logic programming purists disapprove of the cut, because it makes the meaning of a predicate depend on the ordering of the clauses, which is unlike logic in mathematics.

Juho Östman
AHHHHHHHH (like a holy ahhh). Thank you. Thank god im not a purists then right?
Matt
+1  A: 

!/0 also makes this program incomplete, consider for example the most general query with both versions:

?- edu_le(X, Y).

It is often better to use once/1 if you only want a single proof of a particular goal:

?- once(edu_le(hs, phd)).
mat
+1  A: 

In the predicate definition

edu_le(A,B) :- A = B.
edu_le(A,B) :- edu_less(A,B).
edu_le(A,B) :- edu_less(A,C), edu_le(C,B).

the second clause is superfluous and causes repeated generation of answers. Use

edu_le(A,B) :- A = B.
edu_le(A,B) :- edu_less(A,C), edu_le(C,B).

This gives you one true answer, then no more answers (false) on backtracking. You can use a cut in the first clause, but then generating won't work anymore.

?- edu_le(hs,X).
X = hs ;
X = college ;
X = masters ;
X = phd ;
false.

becomes incomplete:

?- edu_le(hs,X).
X = hs.

As mat suggested, use once/1 instead. In a good Prolog implementation, this predicate works as if your program had cuts in strategic places, speeding up your program without disturbing its logical semantics.

larsmans