An Early LISP Program
March 1, 2011
Today we have another exercise in our continuing theme of historical computing, celebrating the publication of the Lisp I Programmer’s Manual on this date fifty-one years ago. Over at his blog Abstract Heresies, LISP/Scheme expert and general curmudgeon Joe Marshall recalls this program from that manual, written by Phyllis Fox:
DEFINE
(((COLLAPSE,(LAMBDA,(L),(COND,
((ATOM,L), (CONS,L,NIL))
((NULL,(CDR,L)),
(COND,((ATOM,(CAR,L)),L),(T,(COLLAPSE,(CAR,L)))))
(T,(APPEND,(COLLAPSE,(CAR,L)),(COLLAPSE,(CDR,L))))))))) ()
COLLAPSE ((((A,B),((C))),((D,(E,F)),(G),((H))))) ()
COLLAPSE ((A,(B,(C,(D,(E))),F,(G,(H,J))))) ()
COLLAPSE ((((((A),B),C),D),E)) ()
STOP))))))))))STOP
The program collapses a nested list into an un-nested one. Here’s the same program in modern Lisp:
(defun collapse (l)
(cond ((atom l) (cons l nil))
((null (cdr l))
(cond ((atom (car l)) l)
(t (collapse (car l)))))
(t (append (collapse (car l))
(collapse (cdr l))))))
Your task is to write a function to un-nest a nested list. When you are finished, you are welcome to read or run a suggested solution, or to post your own solution or discuss the exercise in the comments below.
[…] today’s Programming Praxis exercise, our goal is to write a function to un-nest a list. Let’s get […]
My Haskell solutions (see http://bonsaicode.wordpress.com/2011/03/01/programming-praxis-an-early-lisp-program/ for a version with comments):
Solution 1:
Solution 2:
Solution 3:
Basically a translation:
I was curious whether I could get a more “Pythonic” version going, since this could run up against
Python’s recursion limit if fed a suitably hideous list. Without much time today, I decided to research
what others had come up with; I ran across this “trampolined-style” version, which is certainly stretching my mind a bit.
Here’s a generator that returns the items of the input iterable in “flattened-order”.
You have to collect the output in a list or tuple. Note that handling of strings is
somewhat ambiguous in python, because a string is an iterable. I chose to treat strings
as atoms rather than nested iterables.
Likely to raise an exception if the input is nested more than 1000 deep.
Nice generator, Mike! If you wanted to avoid the import, you could use
and then modify your line 10 as needed (or just call
hasattr(arg, "__iter__")
directly in line 10).[…] Aujourd’hui, j’écrirais ce programme comme ça : ; Flatten a Slist (i.e [Sexp]) ; Slist -> [Symbol] (define collapse (lambda (lst) (mappend collapse-sexp lst))) ; Flatten a Sexp (Symbol | Slist) ; Sexp -> [Symbol] (define collapse-sexp (lambda (sexp) (if (list? sexp) (collapse sexp) (list sexp)))) […]
Thanks Graham.
Here are two non-recursive versions. The first flattens a list ‘in-place’, the second is a generator that works with nested Iterables.
run the code here