Working with lists in Prolog
First off let me state that this is part of a class exercise given as homework. But, the entire assignment is much more involved than the subject of this question. So..
I am searching through two lists given to a predication. My goal is to compare the corresponding elements in this list and determine if the first one is larger. If it is then I need to eventually return a sum of all of those 开发者_如何学编程terms. Here is what I have so far:
isumrow([], [], Iresult) :-
Iresult is 0.
isumrow([Hi1row | Ti1row], [Hi2row | Ti2row], Iresult) :-
if((Hi1row - Hi2row), IsumDiff, Hi1row),
NewIresult is IsumDiff + Iresult,
isumrow(Ti1row, Ti2row, NewIresult),
Iresult is NewIresult.
if(Diff, Iresult, Entry) :-
Diff > 0,
Iresult is Entry.
if(_, Iresult, _) :-
Iresult is 0.
For some reason I am messing up somewhere in my assignments and im not sure where. Any hints would be appreciated. Again, this is part of a much larger assignment that I have working but I cannot get this. Thanks
isumrow([], [], Iresult) :-
Iresult is 0.
isumrow([Hi1row | Ti1row], [Hi2row | Ti2row], Iresult) :-
if((Hi1row - Hi2row), IsumDiff, Hi1row),
NewIresult is IsumDiff + Iresult,
isumrow(Ti1row, Ti2row, NewIresult),
Iresult is NewIresult.
if(Diff, Iresult, Entry) :-
Diff > 0,
Iresult is Entry.
if(_, Iresult, _) :-
Iresult is 0.
I'll try to introduce as little changes as possible to your code.
One thing that is definitely wrong is where you try to calculate the difference. Prolog does arithmetic computations only when using is
operator. Your code:
if((Hi1row - Hi2row), IsumDiff, Hi1row),
is merely passing the expression of the form (X-Y) to the if
predicate, and not calculating it. Later inside if
, you do not compute the difference but try to compare the expression to zero... which fails, because you can only compare numbers to numbers, and not to expressions -- and Diff
gets assigned to an expression.
It would work if you rewrite the first clause of if as follows (even though you should also get rid of that is
here):
if((X-Y), Iresult, Entry) :-
X > Y,
Iresult is Entry.
This way your if
predicate will get X and Y from the expression to be able to compare them.
Also, you need to avoid your if
predicate to yield two possible answers. Your second if
clause will be invoked even when X>Y: in the process of backtracking. The easiest way is to put !
at the end of first clause. It means: "Up to this point, I accept the first solution in this program and I don't want to go back from here to find any other solutions". The clause will be changed to:
if((X-Y), Iresult, Entry) :-
X > Y,
Iresult is Entry,
!.
But... this is good in small programs, and if you actually need backtracking in other parts of your program, this can break it. The cleaner way would be to check proper condition in both clauses. Rewrite them to:
if((X-Y), Iresult, Entry) :-
X > Y,
Iresult is Entry.
if((X-Y), Iresult, _) :-
X =< Y,
Iresult is 0.
Then you're sure that if X>Y, the second clause will fail.
After these modifications your code should work... Please report if it doesn't. It still won't be very prolog-ish though; it is a little bit too verbose.
Edit:
Ok, I'd write it in a simple way:
sum_if_bigger([], [], 0).
sum_if_bigger([A|L1], [B|L2], Result) :-
sum_if_bigger(L1, L2, Partial),
Result is Partial + max(0, A-B).
...or in a tail-recursive way:
sum_if_bigger_tr(L1, L2, R) :-
sum_if_bigger_tr(L1, L2, 0, R).
sum_if_bigger_tr([], [], R, R).
sum_if_bigger_tr([A|L1], [B|L2], Partial, Result) :-
NewPartial is Partial + max(0, A-B),
sum_if_bigger_tr(L1, L2, NewPartial, Result).
精彩评论