Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

GNU Prolog - Recursion issue (easy?)

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 less 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.

like image 282
Matt Avatar asked Dec 21 '22 22:12

Matt


2 Answers

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.

like image 29
Juho Östman Avatar answered Jan 19 '23 16:01

Juho Östman


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.

like image 196
Fred Foo Avatar answered Jan 19 '23 17:01

Fred Foo