1

I am learning Prolog and I got stuck in the code where the knowledge base and base rules are:

   rectangle(a1, 3, 5).  %Name,Width,Height
   rectangle(a2, 1, 2).
   rectangle(a3, 4, 3).

   calcWH(T,C) :-
      rectangle(T,W,_), C is W. % finds the width of the rect.

The recursive part is:

calcWTH([],0). % Base case
calcWTH([H | T ] ,K) :-
   length([H|T],L),
   L =< 3,
   calcWTH(T,M),
   calcWH(H,O),
   K is O+M. 

What I want to do with this code is, with calcWTH I want to calculate total width of the list of rectangles. For example

 calcWTH([a1,a2,a3],A)

returns 8, as expected. The thing I'm puzzled is that this code only works for one way, not the other. For example when I make a query like

calcWTH(A,3) 

It first finds A= [a1], then A=[a2,a2,a2], and afterwards I expect the program to stop because of the part length([H|T],L), L =< 3 But It gets into a loop indefinitely. What am I missing here?

false
  • 10,264
  • 13
  • 101
  • 209
shellnut
  • 25
  • 4
  • 2
    `C is W` is superfluous. Just put `calcWH(T, W) :- rectangle(T, W, _)` (if you wanted to be more verbose, you should use unification, `C = W` not expression evaluation `C is W`). Also, when reasoning over integers, if you want something to "work the other way" you should use CLP(FD) rather than `is/2`, so `K #= O + M`. – lurker May 25 '17 at 12:00

1 Answers1

1

Think about what this is doing:

length([H|T],L), L =< 3
  1. Make a list
  2. Check its length is less than 3, if it is - then success, other wise back track to length/2 and try making another list and then check if that list is length is less than 3.

But we know that list/2 is creating lists in order of larger size, so we know that if list of length 3 fails, then the next list created on back tracking will be bigger and all other lists.. but prolog does not know that. You could imagine writing a length predicate that searchs for lists in a differnt order, maybe randomly, or from a predefined big size to ever smaller lists. Then we would want the backtracking to work as is.

Anyway that is why you get infinite recursion, it will keep trying new lists, of ever increasing size.

You might find adding constraints is a good way to solve your problem:

Using a constrained variable with `length/2`

user27815
  • 4,767
  • 14
  • 28
  • Thanks for the answer. I've solved the problem by adding the following predicate: `lengthP(L,K,B):- length(L,B); A is B+1 , A =< K, lengthP(L,K,A). ` basically calculates all possible length combinations from B( starting with 1), to the constraint K. – shellnut May 25 '17 at 14:24