开发者

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).
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜