Code Comments
Programming Forum and web based access to our favorite programming groups.Just adding up numbers in a list. I already know you could do the below better, cleaner, and in fewer steps. My question is how to tail- recurse it, if possible. (the first arg in the predicate is the list, the second is the "total") Thanks. --------------------- addlist([],0). addlist([X],X). addlist([H|[X]],Y) :- Y is H+X. %This pred is probably unnecessary, but aids my understanding addlist([H1|[H2|T]],Y1) :- addlist([H2|T],Y2), Y1 is H1+Y2.
Post Follow-up to this messageThink I figured out one.... addlist([],0). addlist([X],X). addlist([First|[Second|Rest]],Total) :- Total2 is Total-First, addlist([Second|Rest], Total2).
Post Follow-up to this messageOn Wed, 22 Aug 2007 14:33:56 +0200, <pineapple.link@yahoo.com> wrote: > Think I figured out one.... > > addlist([],0). > addlist([X],X). > addlist([First|[Second|Rest]],Total) :- Total2 is Total-First, > addlist([Second|Rest], Total2). Ingenious, but addlist([1,2,3],T) to calculate the sum does not work. It can only check that the sum you supply is correct. I think you have not found the solution of the exercise yet. :) Note that [A|[B|C]] is the same as [A,B|C]. The second way of writing is easier to read. P.
Post Follow-up to this messageIn article <op.txgr0vo1xbm8ci@eraora>, "Pierpaolo BERNARDI" <pierpaolo@secondbox.net> wrote: > On Wed, 22 Aug 2007 14:33:56 +0200, <pineapple.link@yahoo.com> wrote: > > > Ingenious, but addlist([1,2,3],T) to calculate the sum does not work. > It can only check that the sum you supply is correct. > I think you have not found the solution of the exercise yet. :) > > Note that [A|[B|C]] is the same as [A,B|C]. > The second way of writing is easier to read. > > P. addlist([],0). addlist([X],X). addlist([First, Second|Rest], Total) :- Sum is First+Second, addlist([Sum|Rest], Total).
Post Follow-up to this message> "Pierpaolo BERNARDI" <pierpaolo@secondbox.net> wrote: Thanks (my own personal exercise, BTW - not a class I'm taking). What, exactly, is the "rule" for activating the ability to have Prolog "fill in" a variable... in this case calculating the sum? Is it something to do with "instantiation" or "non-instantiation" of a variable? > addlist([],0). > addlist([X],X). > addlist([First, Second|Rest], Total) :- > Sum is First+Second, > addlist([Sum|Rest], Total). Excellent! Much easier to understand. Now why didn't I think of that?
Post Follow-up to this messageOn Wed, 22 Aug 2007 16:31:46 +0100, Steve Harlow wrote: > addlist([],0). > addlist([X],X). > addlist([First, Second|Rest], Total) :- > Sum is First+Second, > addlist([Sum|Rest], Total). You are now just a small step away from a tailrecursive version, that keeps the head of the list as a separate accumulating parameter: addlist([],0). addlist([X|R],N) :- addlist(R,X,N). addlist([],N,N). addlist([X|R],In,Out) :- NewIn is In + X, addlist(R,NewIn,Out). The usual tailrecursive version of addlist goes like this however: addlist(L,N) :- addlist(L,0,N). <and then the addlist/3 definition above> It is worthwhile trying to give a declarative reading of addlist/3. Tailrecursive predicates are usually associated with an accumulating parameter. There is also a direct relation with a while loop for computing the sum of the list elements in an imperative language: result := 0; % initialize the accumulating parameter while not at end of list result := result + head(list); list := tail(list) Cheers Bart Demoen
Post Follow-up to this message> You are now just a small step away from a tailrecursive version, > that keeps the head of the list as a separate accumulating parameter: I am impressed with your analysis, and code contribution. However, are you saying that the above code (the poster above you, and perhaps my last attempt as well, albeit an uglier version) is NOT tail- recursive? From what I have read, it seems that it should be. It does some work and gets that stuff "out of the way," and then lastly calls itself again. If it is not tail-recursive, can you tell me why not? Thanks.
Post Follow-up to this messageOn Wed, 22 Aug 2007 10:15:45 -0700, pineapple.link wrote: > > I am impressed with your analysis, and code contribution. However, > are you saying that the above code (the poster above you, and perhaps > my last attempt as well, albeit an uglier version) is NOT tail- > recursive? From what I have read, it seems that it should be. It > does some work and gets that stuff "out of the way," and then lastly > calls itself again. > > If it is not tail-recursive, can you tell me why not? Your version was tail-recursive. I should have been more clear and written something like: You are a small step away from a tailrecursive version that at the same time keeps ... as a separate accu. It is kind of a waste to put the accu in a datastructure - but as the other poster noted, quite cunning. Now that I am at it, maybe a little thing on case analysis. if you deal with lists, there are usually only two cases: the empty list and the non-empty list. If you think a predicate that deals with lists needs more than these two cases, there are only the following five possibilities: you are wrong and need to rethink you are wrong and need to rethink you are wrong and need to rethink you are wrong and need to rethink you were right :-) Cheers Bart Demoen
Post Follow-up to this messageThanks - I hope I'm learning a little something here. Tell me - why is it a waste to keep the accumulator in the data structure (albeit cunning, as you mentioned), and what is the advantage of the way you do it? Again, thanks. (It is quite difficult to get the "hang" of this "thinking recursively," but I'm trying, and at least I did come up with a recursive solution, albeit an ugly one, heh)
Post Follow-up to this messageOn Wed, 22 Aug 2007 11:18:39 -0700, pineapple.link wrote: > Thanks - I hope I'm learning a little something here. Tell me - why > is it a waste to keep the accumulator in the data structure (albeit > cunning, as you mentioned), and what is the advantage of the way you > do it? > > Again, thanks. > > (It is quite difficult to get the "hang" of this "thinking > recursively," but I'm trying, and at least I did come up with a > recursive solution, albeit an ugly one, heh) It wasn't ugly. But it is a bit more difficult to understand. Because ... When one tries to give a declarative reading of a predicate, one usually tries to establish a relationship between the arguments of the predicate. For instance for my addlist([],N,N). addlist([X|R],In,Out) :- NewIn is In + X, addlist(R,NewIn,Out). the relationship addlist/3 establishes between its three arguments X,Y and Z is Z equals the sum of Y and the value of every element in X That is made a bit easier by having the extra accumulator argument. When you hide the accumulator inside another argument of a predicate, a similar statement usually becomes more involved. Since you wrote your version of addlist yourself, maybe you should try to come up with a reading that gives a relationship between its arguments. About the waste - let me first repeat your definition of addlist/2 addlist([],0). addlist([X],X). addlist([First, Second|Rest], Total) :- Sum is First+Second, addlist([Sum|Rest], Total). It is clear to us that the recursive call only can match the heads of the second and third clause of addlist/2 - most Prolog systems don't exploit this - XSB is an exception. For most implementations, it is a waste of cpu cycles to construct a list with first element Sum, just to take the list apart in the next activation of addlist - a waste in time and space. But you might not be interested in efficiency of course. The waste is then solely in the brain cycles to understand it, because the reading is more difficult (I'm challenging you for the second time :-) Cheers Bart Demoen
Post Follow-up to this messagePowered by vBulletin
Copyright 2000-2006 Jelsoft Enterprises Limited.