8
votes

If I have this function:

min(List1, List2, Output) :-
   length(List1, N),
   length(List2, M),
   (   N < M ->
       Output = 'true'
   ;   Output = 'false'
   ).

but what if I wanted to also check if N == M? Maybe like this:

min(List1, List2, Output) :-
   length(List1, N),
   length(List2, M),
   (   N < M ->
       Output = 'true'
   ;   (  N = M ->
          Output = 'equal'
       ;  Output = 'other'
       )
   ).

Doesn't seem to work.

2
What, exactly, doesn't seem to work? Are you getting answers you don't expect, or does it not compile?user206428

2 Answers

6
votes

Your nesting of implication (->) looks correct here. Note that, in your definition, N and M will be integers (assuming the calls to length/2 both succeed), so can be compared with == instead of unification (=). In fact, you could even use arithmetic equals in SWI-PROLOG, namely, =:=:

min(List1, List2, Output) :-
    length(List1, N),
    length(List2, M),
    (N < M ->
        Output = 'true'
    ;   (N =:= M ->
            Output = 'equal'
        ;   Output = 'other'
        )
    ).

Testing:

1 ?- min([a],[b],O).
O = equal.

2 ?- min([a,c],[b],O).
O = other.

3 ?- min([a,c],[b,d],O).
O = equal.

4 ?- min([a,c],[b,d,e],O).
O = true.
4
votes

In nested if-then-else, it is common to omit redundant parentheses, yielding:

min(List1, List2, Output) :-
    length(List1, N),
    length(List2, M),
    (   N < M -> Output = true
    ;   N =:= M -> Output = equal
    ;   Output = other
    ).

In Prolog, it is good practice to use pattern matching when possible, because this yields more general, more declarative and more readable programs than using if-then-else. For this particular case of conditions, check out the compare/3 library predicate. compare/3 lets you reify the relation of the two lengths into an atom, and you can use that atom to describe the three conditions with pattern matching:

lists_output(List1, List2, Output) :-
        length(List1, L1),
        length(List2, L2),
        compare(Order, L1, L2),
        order_output(Order, Output).

order_output(<, true).
order_output(=, equal).
order_output(>, other).

Sample queries and results:

?- lists_output([_,_], [_,_,_], Output).
Output = true.

?- lists_output([_,_,_], [_,_,_], Output).
Output = equal.

?- lists_output([_,_,_,_], [_,_,_], Output).
Output = other.