3

I am new to lisp and working on a homework problem to flatten a nested list. I have my funciton working except it needs to 'remove' dotted pairs. So given (1 (2 3) (4 . 5) ((6 7) (89))) my function should output (1 2 3 4 5 6 7 8 9).

So.. my actual question..

Given a dotted pair e.g (1 . 2), how can I get the list '(1 2)?

rcj
  • 631
  • 2
  • 11
  • 27
  • 1
    You may want to experiment with the functions CONS and LIST. There are also a few other useful functions. You should have got some instructions with your lecture. What do you have tried so far? – Rainer Joswig Feb 10 '14 at 16:50
  • 2
    Also, if you search for [\[lisp\] flatten](http://stackoverflow.com/search?q=%5Blisp%5D+flatten), you'll find a number of related questions and answers here. You may be able to find what you're looking for in those. – Joshua Taylor Feb 10 '14 at 17:00
  • Apparently this was pretty straight forward using car and cdr. I'm surprised by how little documentation there is on lisp relative to all of the other languages I've learned. – rcj Feb 10 '14 at 17:33
  • 2
    @rcj There's actually a whole lot out there; a hypertext version of the specification (the HyperSpec) is very good. For this case, you should look at the [car and cdr accessors](http://www.lispworks.com/documentation/HyperSpec/Body/f_car_c.htm) specifically, and chapter [14. Conses](http://www.lispworks.com/documentation/HyperSpec/Body/14_.htm) more generally. – Joshua Taylor Feb 10 '14 at 17:49
  • I guess when I say documentation I'm really talking about the ability to google questions I have. Rather than just picking the one of the first couple google search results for basic questions, I have to sift through the bs and dig really deep into only half-relevant threads to get what I need. – rcj Feb 10 '14 at 22:24
  • @rcj When learning something as complex as a programming language, it will save you hours and hours of time if you make it a point early on to find an authoritative reference (in this case, the HyperSpec), and to skim through the table of contents, and perhaps some sections that look interesting. Obviously you don't need to memorize the whole thing from the beginning, but you'll have an idea of what's out there, and where to find it. A question like this one, to be honest, is about some pretty basic functions in Common Lisp; you're not likely to find many Q&A threads about them, precisely… – Joshua Taylor Feb 11 '14 at 01:49
  • …because they're fairly basic. Even for complex issues, Q&A hunting isn't going to be a great way to learn the standard functionality. That's what the documentation is for. For Lisp, you might also be interested in [lispdoc.com](http://lispdoc.com/), "a search engine for documentation of the Common Lisp programming language and many of its libraries." It searches the HyperSpec, some other useful books, and libraries. – Joshua Taylor Feb 11 '14 at 01:51
  • There's also some meta-searching that you should be doing too: while this isn't a perfect heuristic, if you're searching for solutions to some task, and it doesn't seem like anyone's ever done it before, then you might want to ask whether it's the most suitable approach. In this case (as the results for `[lisp] flatten` show) there are lots of solutions to flattening lists that don't require turning `'(1 . 2)` into `(1 2)`. – Joshua Taylor Feb 11 '14 at 01:53

1 Answers1

10

A cons cell is a structure that has two parts, called its car and its cdr. The pair (1 . 2) is a cons cell whose car is 1 and whose cdr is 2. Lists in Lisps are built up from cons cells and nil. How this works is described in lots of places, including the answer to Recursive range in Lisp adds a period? A list is either the empty list () (also called nil), or a cons whose car is the first element of the list and whose cdr is another list which is the rest of the list. That means that a list

(1 2)

is built of cons cells and nil as

(cons 1 (cons 2 nil))

If you've already got (1 . 2), then you can get 1 and 2 with car and cdr. You'd put them back together as just described. That is,

(let ((x '(1 . 2)))
  (cons (car x) (cons (cdr x) nil)))

Alternatively, you could just use list:

(let ((x '(1 . 2)))
  (list (car x) (cdr x)))

If you want to reuse the same cons cell, you could replace the cdr of the cell with (cons 2 nil). For instance (and note that we're not quoting the pair anymore, because modifying literal data is undefined behavior):

(let ((x (cons 1 2)))
  (setf (cdr x) (cons (cdr x) nil))
  x)

That could also be

(let ((x (cons 1 2)))
  (setf (cdr x) (list (cdr x)))
  x)

You could also use rplacd:

(let ((x (cons 1 2)))
  (rplacd x (list (cdr x)))
  x)
Community
  • 1
  • 1
Joshua Taylor
  • 84,998
  • 9
  • 154
  • 353