0

I am having trouble with some lisp code. This function is just supposed to reverse a basic list. I can only use primitives, which are defined as " defun, cond, cons, car, cdr, null, eq, listp, atom, symbolp, +, -­‐ , <, >"

In the example of passing (1 2 3 4) I get back (((4 3) 2) 1)

(defun reverse2 (l)
(cond
    ((eq nil (cdr l)) (car l) )
    (t (cons(reverse2 (cdr l)) (cons (car l) nil)))))

Please let me know how to improve this. This is NOT for homework, I'm just working on this as an exercise for my final tomorrow.

colin
  • 127
  • 1
  • 1
  • 9

3 Answers3

1

To implement a reverse function, you need to use an accumulator. Here is how you might implement this (in this case, tail is the accumulator):

(defun revappend (list tail)
  (cond ((null list) tail)
        (t (revappend (cdr list) (cons (car list) tail)))))

Then, implement reverse in terms of revappend:

(defun reverse (list)
  (revappend list nil))
C. K. Young
  • 219,335
  • 46
  • 382
  • 435
  • but you (define and) use `revappend`, which is not a primitive. the point is [to use only primitives](http://stackoverflow.com/questions/19529829/how-to-recursively-reverse-a-list-using-only-basic-operations) from the given list. – Will Ness Dec 11 '14 at 21:01
  • 1
    @WillNess `defun` is an approved primitive. If it's allowed, by extension you must be allowed to define your own functions. – Tyler Dec 11 '14 at 23:09
  • @Tyler then the puzzle makes no sense. You would just redefine the whole standard library on your own. That's not the point here. Did you look at the entry I linked? – Will Ness Dec 11 '14 at 23:36
  • @WillNess I understood the point of the puzzle was to force the student to reimplement parts of the standard library as a learning exercise. – Tyler Dec 12 '14 at 16:23
0

If you would want to use simple recursion, then you would have to append the first item to the end of the list. Note that this is not a good implementation of a list reverse operation. Why?

(defun reverse2 (l)
   (cond ((endp l) l)                                                                                                                
         (t (append (reverse2 (rest l))                                                                                                     
                    (list (first l))))))
REVERSE                                                                                      
CL-USER> (reverse2 '(a b c d))
(D C B A)                                                                                                                                
Rainer Joswig
  • 136,269
  • 10
  • 221
  • 346
  • What about an implementation using cons instead of append? For the purpose of my course we are not allowed append. Just judging from your code I assume (rest l) is equivalent to (cdr l) and (first l) is equivalent to (car l). Please correct me if I am wrong in this instance. – colin Dec 11 '14 at 07:00
  • @colin you can try to implement APPEND and see how it goes. For the Lisp primitives see a Lisp manual. No need to 'assume' what they do. Please consult a manual. – Rainer Joswig Dec 11 '14 at 07:05
  • my course defined the primitives as the ones I mentioned above, and therefore we did not learn about append. Same with rest and first which is why I defined it in the first place in my initial post. – colin Dec 11 '14 at 07:12
  • @colin Rainer's point is that if you want to use a non-accumulative solution, you have to implement `append` and use that, and it's a poor solution because your reverse operation would be O(n²) instead of O(n) (which the `revappend` solution is). – C. K. Young Dec 11 '14 at 07:13
  • @Colin: your course uses old function names for list processing operations. Current practice uses slightly newer ones. Please consult a manual. – Rainer Joswig Dec 11 '14 at 07:16
  • @RainerJoswig Re newer list operations, surely you'd be using `endp` instead of `null`? ;-) – C. K. Young Dec 11 '14 at 07:25
  • @ChrisJester-Young: Note also that accumulative version is also not that good, since Lisp does not provide TCO in the standard. TCO is widely available in many compiled implementations, but not in ABCL and often not in Interpreters. Thus 'real' Lisp uses different implementations with destructive modifications of cons cells. – Rainer Joswig Dec 11 '14 at 07:41
  • @RainerJoswig Agree re TCO, and I would have used a `do` or `loop` normally, but those aren't in the list of allowable operations from the OP. :-) – C. K. Young Dec 11 '14 at 07:56
  • `append` is not on the list of allowed primitives. [this was asked and answered before](http://stackoverflow.com/questions/19529829/how-to-recursively-reverse-a-list-using-only-basic-operations). – Will Ness Dec 11 '14 at 21:04
  • @RainerJoswig re "Lisp standard" I think "Lisp" here is used in a wider sense, not as a "Common Lisp" stand-in. That's also probably the reason for the short list of allowed primitives - it's just a learning riddle. – Will Ness Dec 11 '14 at 21:09
  • @WillNess: True, But it's useful to understand for students that this is not real Lisp code for any useful Lisp dialect. It's not coming from a real practical programming problem, but coming from tasks in computer science education for learning abstract concepts with a limited set of operators. Just as useful for actual programming as Turing machines are... – Rainer Joswig Dec 11 '14 at 21:42
  • @RainerJoswig it's a *little* bit easier than that... plus, they get to think about some concepts, like induction/recursion here, which helps in general problem-solving. – Will Ness Dec 11 '14 at 22:29
  • @Rainer Joswig I understand there may be little 'practical sense' in learning the'lisp' we are for our course. However, the course is not about learning lisp, but rather learning how to think in a different way by becoming familiar with a different type of programming language (in this case functional programming). Sure, I could consult a manual and I would do that if I wanted to actually learn lisp. Rather, I wanted to learn the thought process behind lisp rather than the actual language since that is what my course is about. – colin Dec 13 '14 at 09:35
0

Instead of using an auxillary function you can use an optional argument:

(defun reverse (list &optional tail)
  (cond ((null list) tail)
        (t (reverse (cdr list)
                    (cons (car list) tail)))))
Sylwester
  • 47,942
  • 4
  • 47
  • 79