reverse not working: CL-USER> (rvrs '(1 2 3)) (((NIL . 3) . 2) . 1)

This is a discussion on reverse not working: CL-USER> (rvrs '(1 2 3)) (((NIL . 3) . 2) . 1) within the lisp forums in Programming Languages category; ssecorp wrote: > On Aug 23, 6:55 pm, Kenny <kentil...@gmail.com> wrote: > >>ssecorp wrote: >> >>>my reverse: >>>(defun rvrs (lista) >>> (if (null lista) >>> '() >>> (cons (rvrs (cdr lista)) (car lista)))) >> >>>CL-USER> (rvrs '(1 2 3)) >>>(((NIL . 3) . 2) . 1) >> >>>built-in: >>>CL-USER> (reverse '(1 2 3)) >>>(3 2 1) >> >>>So my reverse gets the spirit right but doesnt deliver exactly what I >>>want. How do I cons without adding dots? >> >>Do you know what a cons is, and how a proper list is defined in terms of >>conses? >> >>kt > ...

Go Back   Application Development Forum > Programming Languages > lisp

Object Mix

Register FAQ Calendar Search Today's Posts Mark Forums Read
  #11  
Old 08-23-2008, 03:21 PM
Kenny
Guest
 
Default Re: reverse not working: CL-USER> (rvrs '(1 2 3)) (((NIL . 3) . 2). 1)

ssecorp wrote:
> On Aug 23, 6:55 pm, Kenny <kentil...@gmail.com> wrote:
>
>>ssecorp wrote:
>>
>>>my reverse:
>>>(defun rvrs (lista)
>>> (if (null lista)
>>> '()
>>> (cons (rvrs (cdr lista)) (car lista))))

>>
>>>CL-USER> (rvrs '(1 2 3))
>>>(((NIL . 3) . 2) . 1)

>>
>>>built-in:
>>>CL-USER> (reverse '(1 2 3))
>>>(3 2 1)

>>
>>>So my reverse gets the spirit right but doesnt deliver exactly what I
>>>want. How do I cons without adding dots?

>>
>>Do you know what a cons is, and how a proper list is defined in terms of
>>conses?
>>
>>kt

>
>
> yes


no.

Show us how to create the list (1 2) using only cons.

then take that list and the list (3 4) and create (1 2 3 4) using only
cdr and setf. it's ok if the solution works only if the first list is
length 2.

kt
Reply With Quote
  #12  
Old 08-23-2008, 03:49 PM
Pascal J. Bourguignon
Guest
 
Default Re: reverse not working: CL-USER> (rvrs '(1 2 3)) (((NIL . 3) . 2) . 1)

ssecorp <circularfunc@gmail.com> writes:
> but Im still trying to figure out how to do it with just one simple
> reucrsive function just as an exercise.


Doing it with a simple recursive function, you will either need a lot
of time, or a little more space.


Assume you want to reverse list = (a b c d e)

(first list) = a
(rest list) = (b c d e)

(rev (rest list)) = (e b c d)

which is almost what you want, only with a appended. If you use
(nconc (rev (rest list)) (list (first list))) you will spend O(N^2)
time walking the reversed sublists to add the last element. And if
you use append instead of nconc, you will allocate also O(N^2)
temporary cons cells.


So let's do otherwise. Instead of taking the reverse of the rest, you
could remark that
(rev (list (first list))) == (list (first list)) == (a)
and that you can build (b a), the reverse of list = (a b)
with (cons (first (rest list)) (list (first list)))

Then you can build the reverse of the list by taking the first
element, and cons it to the resulting, reversed list. You need two
parameters:

(defun rev (list reversed) ...)

(rev '(a b c) '()) --> (c b a)



--
__Pascal_Bourguignon__ _ Software patents are endangering
() ASCII ribbon against html email (o_ the computer industry all around
/\ 1962O20I=1.100 //\ the world http://lpf.ai.mit.edu/
2001:my($f)=`fortune`; V_/ http://petition.eurolinux.org/
Reply With Quote
  #13  
Old 08-24-2008, 03:35 AM
Tamas K Papp
Guest
 
Default Re: reverse not working: CL-USER> (rvrs '(1 2 3)) (((NIL . 3) . 2) .1)

On Sat, 23 Aug 2008 09:25:34 -0700, ssecorp wrote:

> So my reverse gets the spirit right but doesnt deliver exactly what I
> want. How do I cons without adding dots?


Please do yourself a favor and read (up to) Chapter 3 of Graham's ANSI
Common Lisp.

Tamas
Reply With Quote
  #14  
Old 08-24-2008, 06:03 AM
ardaliev
Guest
 
Default Re: reverse not working: CL-USER> (rvrs '(1 2 3)) (((NIL . 3) . 2) .1)

On Aug 23, 6:25*pm, ssecorp <circularf...@gmail.com> wrote:
> my reverse:
> (defun rvrs (lista)
> * (if (null lista)
> * * * '()
> * * * (cons (rvrs (cdr lista)) (car lista))))
>
> CL-USER> (rvrs '(1 2 3))
> (((NIL . 3) . 2) . 1)
>
> built-in:
> CL-USER> (reverse '(1 2 3))
> (3 2 1)
>
> So my reverse gets the spirit right but doesnt deliver exactly what I
> want. How do I cons without adding dots?




( defun my-reverse ( list)
(if ( null list)
nil
(append ( my-reverse ( cdr list)) (list ( car list)))))
Not very elegant, but it works!!
Reply With Quote
  #15  
Old 08-24-2008, 12:22 PM
Kent M Pitman
Guest
 
Default Re: reverse not working: CL-USER> (rvrs '(1 2 3)) (((NIL . 3) . 2) . 1)

ardaliev <ardaliev@gmail.com> writes:

> On Aug 23, 6:25Â*pm, ssecorp <circularf...@gmail.com> wrote:
> > my reverse:
> > (defun rvrs (lista)
> > Â* (if (null lista)
> > Â* Â* Â* '()
> > Â* Â* Â* (cons (rvrs (cdr lista)) (car lista))))
> >
> > CL-USER> (rvrs '(1 2 3))
> > (((NIL . 3) . 2) . 1)
> >
> > built-in:
> > CL-USER> (reverse '(1 2 3))
> > (3 2 1)
> >
> > So my reverse gets the spirit right but doesnt deliver exactly what I
> > want. How do I cons without adding dots?


These first remarks are to ssecorp:

The dots are not really there. They are visual artifact, not something in
your code. All lists have them, but they are almost always not shown to
you. That is,

(a . (b . (c . ())))

is the same as (a b c), the printer just doesn't show you. But the dot is
there. What the dot tells you, when you see it appear, is that none of the
shorthand rules for eliding the dot applies. Since all of the shorthanding
rules rely on there being a proper list to the right of the dot, what this
tells you is that you've built a cons that is not a proper list; that is,
it is not a list whose righthand backbone ultimately terminates in an
empty list. And since the reverse of a proper list is a proper list, what
you're really learning is that you have not correctly constructed either the
base case [which is fine here] or the inductive step.

So consider your inductive step:

(cons (rvrs (cdr lista)) (car lista))

What this implies is that there is some list

( first . rest )

such that

( rest . first )

is its reverse. And that assumption is false. The reverse of a right-handed
list is not a left-handed list. It is a right-handed list that has its
elements in the other order. That is,

(1 2 3)

which is the list

(1 . (2 . (3 . ())))

must reverse to

(3 . (2 . (1 . ())))

not to

(((() . 3) . 2) . 1)

So you must write the recursion differently. I'm not going to do that
for you. But hopefully seeing that the dot is not the problem but rather
your understanding of the structure to be achieved is the problem, you'll
get there.

Getting back to ardaliev's reply:

> ( defun my-reverse ( list)
> (if ( null list)
> nil
> (append ( my-reverse ( cdr list)) (list ( car list)))))
> Not very elegant, but it works!!


It's partly not elegant because of the spaces between th open parens
and the operators. That's a superficial matter, but you should definitely
avoid this. There are many variations of good Lisp style, but there is
almost no reason for ever doing this. [I could cite exceptions. Nearly all
style rules have exceptions, after all. But I know of no exceptions that
would apply here.]

The really inelegant part is the call to APPEND. APPEND is an O(n),
not an O(1) function. In sloppy terms, it means it has to do work
proportional to the number of elements in the list it's appending to.
That is, if you're adding one element to the end of an n-length list
inside a loop from 0 to n, then APPEND will get called, on average n/2
(the average length of the list) times n (the number of times you
looped) or 1/2 n^2, which we notate as just O(n^2) ignoring the constant
factor of 1/2 because as the problem goes, the dominant bit of interest
is the exponent, not the constant factor.

Anything O(n^2) can be trouble even if n gets only moderately large.
You're better off sticking to CONS when you're in a loop, since it is
O(1). That doesn't mean you can just substitute CONS for APPEND and
be done with it--it's not the same function, and so what you have to
do with CONS is different. But it does mean when you see APPEND in a
loop [or in a recursion] in your code, you should always be nervous
and double-checking your algorithmic complexity VERY carefully.

So the speed issue is the true inelegance of what you offer, and in
truth although what you have is probably functionally correct (returns
the intended answer--I didn't try it, actually, but it looks
plausible), it's a major hurdle in the learning of Lisp that you must
not accept this as correct because there is more to a program,
especially a very general subroutine like a REVERSE function, than
functional correctness. If you tolerate algorithmic inefficiency,
your programs (even when compiled with heavy optimization) will run
very slowly when they get to even intermediate size, and you'll
probably blame the language rather than your own coding. (That's
convenient if you're in the kind of verbal debate where people don't
do much fact-checking and want to believe an unfounded claim that Lisp
is slow anyway; you'll probably find many people rushing to agree with
you because they want to believe that Lisp is slow and they applaud
you for 'proving' it. But it's less good if you actually care about
what the truth of why your program runs slowly is.)
Reply With Quote
  #16  
Old 08-28-2008, 01:52 AM
Madhu
Guest
 
Default Re: reverse not working: CL-USER> (rvrs '(1 2 3)) (((NIL . 3) . 2) . 1)


* Frank Buss <12gp6bgi1a0zr$.tfebivh3tkwl$.dlg@40tude.net> :
Wrote on Sat, 23 Aug 2008 19:39:57 +0200:

| One idea would be to implement (a slightly modified) useful Haskell
| function like this one:
|
| (defun foldl (fun id list)
| (if list
| (foldl fun
| (funcall fun (car list) id)
| (cdr list))
| id))
|
| (defun rvrs (list)
| (foldl #'cons nil list))

[SNIP]

| Of course, Common Lisp doesn't guarantee to be tail recursive, so for long
| lists you would use something like this:
|
| (defun rvrs (list)
| (loop for i in list
| with result = nil
| do (push i result)
| finally (return result)))
|
| And for sum you would just write (reduce #'+ list).

I hope you aren't forgetting REDUCE (with :FROM-END argument) _is_
FOLDL/FOLDR.

I think your definition of FOLDL could be written as

(defun foldl (fun id list)
(reduce (lambda (x y) (funcall fun y x)) list :initial-value id))

without worrying about tail recursion

I notice I sometimes do not want to use `FOLDL' or `FOLDR' explicitly
when I can just use the REDUCE expression: The rationale is the same as
using anonymous functions i.e. using a LAMBDA instead of naming that
abstraction.

--
Madhu

Reply With Quote
Reply


Thread Tools
Display Modes


All times are GMT -5. The time now is 01:20 AM.


Powered by vBulletin® Version 3.7.2
Copyright ©2000 - 2008, Jelsoft Enterprises Ltd.
Search Engine Optimization by vBSEO 3.2.0
vB Ad Management by =RedTyger=

In an effort to better serve ads to our visitors, cookies are used on objectmix.com. For more information, check out our Privacy Policy.