Can anyone help me reverse a list in Lisp without using the reverse function?

In summary: What I'm not sure of is how it gets to that bit as won't the recursion keep happening before this part?The last branch that starts with t is like the default clause. It executes always unless some other branch executed before, because the condition of this default branch is always true.Yes. The default clause is always executed, unless there is a more specific clause that overrides it.
  • #1
JamesBwoii
74
0
Hi, I'm trying to reverse a list in Common Lisp without using the reverse function.

I've had a go but it's not working. Can anyone help?

Code:
(defun my-reverse(my-list)
  (cond
    ((null my-list) nil)
    (t (append (my-reverse(cdr my-list))
	       (list (car my-list))))))
Thanks.
 
Technology news on Phys.org
  • #2
What exactly is not working? I don't have Common Lisp installed, but I tried your code in Emacs Lisp, and it seems to work.
 
  • #3
Evgeny.Makarov said:
What exactly is not working? I don't have Common Lisp installed, but I tried your code in Emacs Lisp, and it seems to work.

That's strange. I am using Emacs, SBLC and slime. I think it could be because I'm not running it right, I'm new to Lisp and not completely sure how it works.

I'm trying to run it:

Code:
(my-reverse (1 2 3))
Here's the error

Code:
; SLIME 2014-10-10; compiling (DEFUN MY-REVERSE ...)
CL-USER> (my-reverse (1 2 3))
; in: MY-REVERSE (1 2 3)
;     (1 2 3)
; 
; caught ERROR:
;   illegal function call
; 
; compilation unit finished
;   caught 1 ERROR condition

I assume the illegal function call means that I am calling it wrong but I've called other, simpler, functions I've made that way and they've worked.

Cheers.
 
  • #4
The notation [m](f a b c)[/m] in Lisp denotes function application. To interpret it as a list, you need to "deactivate" it, i.e., declare that it is a list constant rather than the result of a function call. This is done using the function [m]quote[/m]. For example, [m](quote (f a b c))[/m] is a list containing three symbols [m]f[/m], [m]a[/m], [m]b[/m] and [m]c[/m]. A shorthand for [m]quote[/m] is the prime [m]'[/m]. So you should invoke your function as [m](my-reverse '(1 2 3))[/m].
 
  • #5
Evgeny.Makarov said:
The notation [m](f a b c)[/m] in Lisp denotes function application. To interpret it as a list, you need to "deactivate" it, i.e., declare that it is a list constant rather than the result of a function call. This is done using the function [m]quote[/m]. For example, [m](quote (f a b c))[/m] is a list containing three symbols [m]f[/m], [m]a[/m], [m]b[/m] and [m]c[/m]. A shorthand for [m]quote[/m] is the prime [m]'[/m]. So you should invoke your function as [m](my-reverse '(1 2 3))[/m].

Thanks, slight annoyed with myself as I knew that, just had forgotten!

Despite having written it, I needed to look up most of it so am not sure I understand most of it. I think it works like this.

Code:
(defun my-reverse(my-list)                         ;define a function with parameter
  (cond                                                     ; essentially an 'if' statement
    ((null my-list) nil)                                  ;empty list is false
    (t (append (my-reverse(cdr my-list))         ;true 
	       (list (car my-list))))))

  • Define a function with the paramter 'my-list'
  • Essentially an if statement
  • Empty list is false
  • True. Append(Recursively go back to the function with cdr, so the list without the first element.
  • This is what I'm not sure about. Car of the list is the first element so is 'list' being added to with the first element? What I'm not sure of is how it gets to that bit as won't the recursion keep happening before this part?
 
  • #6
[m]cond[/m] is like [m]switch[/m] in C-like languages, but with arbitrary conditions instead of just comparing with constants. The last branch that starts with [m]t[/m] is like the [m]default[/m] clause. It executes always unless some other branch executed before, because the condition of this default branch is always true.

JaAnTr said:
Empty list is false
It is true that in CL the empty list [m]nil[/m] also fulfills the role of the Boolean constant False. (Such conflation is not necessarily a good thing for the clarity of the language semantics.) But here it does not behave as False; it behaves (is returned) as the empty list.

JaAnTr said:
This is what I'm not sure about. Car of the list is the first element so is 'list' being added to with the first element?
Yes. This construction: [m](append ... (list (car my-list)))[/m] is necessary because, I think, there is no built-in function that adds an element to the end of a list (I may be wrong about CL in this), so we have to use [m]append[/m], and it requires both arguments to be lists.

JaAnTr said:
What I'm not sure of is how it gets to that bit as won't the recursion keep happening before this part?
Yes, the recursive call happens before [m]append[/m]. This is a mind-twisting thing about recursion. First, note that the recursion eventually stops because the function is called with smaller and smaller lists. But yes, the complete recursive call (which gives rise to other recursive calls) has to finish before [m]append[/m] is executed.

The correctness of this program is easy to understand: if we denote concatenation by $\cdot$, then $\operatorname{reverse}(x\cdot l)=\operatorname{reverse}(l)\cdot x$. But to trace this program in one's head may be quite difficult. I call this the "magic" aspect of some well-designed programming languages: it is often easier to write a program than to understand how it works.
 
  • #7
That makes sense, and you're right, getting my head around recursion is quite difficult.

I've found some code online which reverses a list that has lists in it but I don't quite get it and was hoping that you could explain a bit of it.

Code:
(defun my-reverse (l)
  (cond ((null l) nil)
        ((listp (car l)) 
	 (append (my-reverse (cdr l)) 
         (list (my-reverse (car l)))))
        (t
          (append (my-reverse (cdr l)) 
                  (list (car l))))))

What I don't get is this part.

Code:
  (cond ((null l) nil)
        ((listp (car l)) 
	 (append (my-reverse (cdr l)) 
         (list (my-reverse (car l)))))

I assume that is the bit which reverse a list inside another list. What I don't understand is that isn't it saying that if the list is empty then it executes the 3 lines of code after it?

Is it then creating a listp with the first element of list l?
Then appending by recursively go back to the function with cdr, so the list without the first element.
Then creating a list by recursively going back to the function with the first element of the list?

I really don't see how that is working.
 
  • #8
JaAnTr said:
Code:
  (cond ((null l) nil)
        ((listp (car l)) 
	 (append (my-reverse (cdr l)) 
         (list (my-reverse (car l)))))

I assume that is the bit which reverse a list inside another list. What I don't understand is that isn't it saying that if the list is empty then it executes the 3 lines of code after it?
The [m]cond[/m] clause dealing with the case when [m]l[/m] is empty is [m]((null l) nil)[/m]. The next clause handles the case when [m](listp (car l))[/m] is true, i.e., the head of [m]l[/m] is a list. So, if [m]l[/m] is empty, return the empty list. If the head of [m]l[/m] is itself a list, then reverse the tail of [m]l[/m], reverse the head, and add the reversed head as the last element of the reversed tail.
 

FAQ: Can anyone help me reverse a list in Lisp without using the reverse function?

How can I reverse a list in Lisp?

To reverse a list in Lisp, you can use the reverse function. This function takes in a list as its argument and returns a new list with the elements in reverse order. For example, if you have a list (1 2 3 4), the reverse function will return (4 3 2 1).

Is there a built-in function for reversing a list in Lisp?

Yes, as mentioned before, the reverse function is built-in to Lisp and is specifically designed for reversing lists. This function is part of the Common Lisp standard and can be used in any Lisp interpreter or compiler.

Can I reverse a list in-place in Lisp?

No, Lisp does not have a built-in function for reversing a list in-place. This means that the original list will remain unchanged and a new reversed list will be created. However, you can write your own function to achieve an in-place reversal if needed.

What happens if I try to reverse a non-list object in Lisp?

If you try to use the reverse function on a non-list object, you will get an error. This is because the reverse function only works on lists. If you want to reverse a non-list object, you will need to convert it into a list first and then apply the reverse function.

How efficient is the reverse function in Lisp?

The reverse function in Lisp has a time complexity of O(n), where n is the length of the list. This means that the time it takes to reverse a list will increase as the size of the list increases. However, in most cases, the reverse function is considered to be efficient and performs well even on large lists.

Back
Top