2
votes

So I am learning Prolog. I need to write a predicate that finds the min/max value of an integer list. For example, the query minmaxArray([4,-1,5,4,1,2,3,-2],X,Y) would return X = -2 Y = 5. Here is what I have so far:

    %min/max element of a 1 item list is that item.

    minmaxArray([X], X, X).

%when there is only 2 items, put the smaller element in A and the 
%larger element in B

    minmaxArray([X,Y], A, B) :- mymin(X,Y,Min), 
    A is Min, mymax(X,Y,Max), B is Max.

%when there is more than two items make a recursive call to find the min/max
%of the rest of the list.

    minmaxArray([X,Y|T], A, B) :- minmaxArray([Y|T], M, K), 
    mymin(X,M,Temp), A is Temp, mymax(X,K,Temp2), B is Temp2.

Assume mymin and mymax predicates work properly. They return the min and max of 2 numbers.

The issue here is that for example when I query minmaxArray([4,-1,5],X,Y) it returns X = -1 Y = 5 and then again X = -1 Y = 5. I know this must be because it hits the 2nd condition on the recursive call. I only want it to return X = -1 Y = 5 one time. I tried replacing condition 3 with this:

minmaxArray([X,Y,_|T], A, B) :- minmaxArray([Y,_|T], M, K), 
    mymin(X,M,Temp), A is Temp, mymax(X,K,Temp2), B is Temp2.

but that crashes the program. What can I do to fix this?

Note: I know that I may not be using the terminology correctly by saying returning and saying predicate when it should be rule, etc so I apologize in advance.

3
You don't need is/2 at all--you're not doing any arithmetic. You can just say minmaxArray([X,Y], Min, Max) :- mymin(X,Y,Min), mymax(X,Y,Max). - Daniel Lyons
You can use min(X,Y) built in as, Min is min(X,Y) to obtain the minimum of two values. Likewise for max. That might make your life a little simpler. And to build on @DanielLyons comment, don't use is to unify terms. Use =/2. So for example, B = Temp2, not B is Temp2. Also as pointed out, you can avoid that step altogether by unifying them right in the argument list, as his example shows. - lurker
Ok, so I am totally new to this and this may be a stupid question but what is =/2 and when you say not to use is and use = instead, is that because 'is' is used when you want to evaluate an arithmetic operation? Thanks! - Rob L
The notation predicate/N is the name of the predicate with the arity (number of arguments). =/2 is = and is/2 is is (that's easy to read!). You use =/2 when you want to explicitly unify two terms and you use is/2 when you want to unify the variable or value on the left side with the result of evaluating the arithmetic expression on the right side. - Daniel Lyons
By the way, "predicate" is correct nomenclature, but "return" is not. Moreover, you're not crashing the program, it's just failing. - Daniel Lyons

3 Answers

2
votes

Seems that your code could be simpler. This predicate does all what's needed, and attempt to show how to use some standard construct (if/then/else)

minmaxArray([X], X, X).
minmaxArray([X|R], Min, Max) :-
    minmaxArray(R, Tmin, Tmax),
    ( X < Tmin -> Min = X ; Min = Tmin ), % or mymin(X,Tmin,Min)
    ( X > Tmax -> Max = X ; Max = Tmax ).
2
votes

You have provided 2 ways of solving the case where there are 2 items: one explicitly for 2 items, and your general case, which then employs the 1 element case.

Solution: remove the unneeded 2-element case.

1
votes

Or, tail-recursive:

minmax([X|Xs],Min,Max) :- % we can only find the min/max of a non-empty list.
  minmax(Xs,(X,X),Min,Max)  % invoke the helper with the min/max accumulators seeded with the first item
  .

minmax([],(Min,Max),Min,Max).    % when the source list is exhausted, we're done: unify the accumulators with the result
minmax([X|Xs],(M,N),Min,Max) :-  % when the source list is non-empty
  min(X,M,M1) ,                  % - get a new min value for the accumulator
  max(X,N,N1) ,                  % - get a new max value for the accumulator
  minmax(Xs,(M1,N1),Min,Max)     % - recurse down on the tail.
  .

min(X,Y,X) :- X =< Y . % X is the min if it's less than or equal to Y.
min(X,Y,Y) :- X >  Y . % Y is the min if it's greater than X.

max(X,Y,X) :- X >= Y . % X is the max if it's greater than or equal to Y.
max(X,Y,Y) :- X <  Y . % Y is the max if it's greater than X.