From: ·········@gmail.com
Subject: is it effective/better
Date: 
Message-ID: <1155745112.882254.266180@b28g2000cwb.googlegroups.com>
i have just wrote a pascal's triangle program , since i'm a newbie to
lisp, i dont know whether what i have written is an effective solution.
can any one check this out... thankx in advance


(defun pascal (rows)
  (do ((i 1 (1+ i))) ((> i rows))
    (do ((sp (- rows i) (1- sp))) ((= 0 sp)) (format t "  "))
    (do ((j 1 (1+ j))) ((> j i))
      (format t "~3a " (pasc i j)))
    (format t "~%")))


(defun pasc (row col)
  (cond ((or (< col 1) (< row 0)) 0)
	((= col 1) 1)
	((= col row) 1)
	(t (+ (pasc (- row 1) (- col 1)) (pasc (- row 1) col)))))


CL-USER> (pascal 12)
                      1
                    1   1
                  1   2   1
                1   3   3   1
              1   4   6   4   1
            1   5   10  10  5   1
          1   6   15  20  15  6   1
        1   7   21  35  35  21  7   1
      1   8   28  56  70  56  28  8   1
    1   9   36  84  126 126 84  36  9   1
  1   10  45  120 210 252 210 120 45  10  1
1   11  55  165 330 462 462 330 165 55  11  1

From: Kaz Kylheku
Subject: Re: is it effective/better
Date: 
Message-ID: <1155749463.265193.84310@m79g2000cwm.googlegroups.com>
·········@gmail.com wrote:
> i have just wrote a pascal's triangle program , since i'm a newbie to
> lisp, i dont know whether what i have written is an effective solution.

Effective as in what? Having effect? What kind of effect are you
looking for?

Your program does have the intended effect of printing out the first
several
rows of Pascal's Triangle.

Moreover, it looks pretty, provided that the numbers don't grow beyond
three digits.

> (defun pasc (row col)
>   (cond ((or (< col 1) (< row 0)) 0)
> 	((= col 1) 1)
> 	((= col row) 1)
> 	(t (+ (pasc (- row 1) (- col 1)) (pasc (- row 1) col)))))

Ouch! You are doing full recursion all the way to the top of the
triangle in order to compute each cell in the triangle.

Most programs that print the triangle keep a buffer so the next row can
be computed in the straightforward way from the previous row.

Memoization of the pasc function will do effectively the same thing. It
means that once you compute (pasc x y) for some X and Y, the result is
not only returned but also cached in a storage object associated with
the function. The next time (pasc x y) is called with the same X and Y,
it will retrieve the previously computed result from the cache.

There is at least one memoization packages for Lisp which simply lets
you annotate a function as memoized. The nice thing about this is that
you don't have to change the structure of your program at all.
From: ·········@gmail.com
Subject: Re: is it effective/better
Date: 
Message-ID: <1155813918.248697.111890@p79g2000cwp.googlegroups.com>
Kaz Kylheku wrote:
> ·········@gmail.com wrote:
> > i have just wrote a pascal's triangle program , since i'm a newbie to
> > lisp, i dont know whether what i have written is an effective solution.
>
> Effective as in what? Having effect? What kind of effect are you
> looking for?
>
> Your program does have the intended effect of printing out the first
> several
> rows of Pascal's Triangle.
>
> Moreover, it looks pretty, provided that the numbers don't grow beyond
> three digits.
>
> > (defun pasc (row col)
> >   (cond ((or (< col 1) (< row 0)) 0)
> > 	((= col 1) 1)
> > 	((= col row) 1)
> > 	(t (+ (pasc (- row 1) (- col 1)) (pasc (- row 1) col)))))
>
> Ouch! You are doing full recursion all the way to the top of the
> triangle in order to compute each cell in the triangle.
>

yes , u are right, can i print the number along when i'm finding the
values, .. within the recursion, (instead of caching)
From: John Stoneham
Subject: Re: is it effective/better
Date: 
Message-ID: <1155752405.841234.42170@m79g2000cwm.googlegroups.com>
·········@gmail.com wrote:
> i have just wrote a pascal's triangle program , since i'm a newbie to
> lisp, i dont know whether what i have written is an effective solution.
> can any one check this out... thankx in advance
>
>
> (defun pascal (rows)
>   (do ((i 1 (1+ i))) ((> i rows))
>     (do ((sp (- rows i) (1- sp))) ((= 0 sp)) (format t "  "))
>     (do ((j 1 (1+ j))) ((> j i))
>       (format t "~3a " (pasc i j)))
>     (format t "~%")))
>
>
> (defun pasc (row col)
>   (cond ((or (< col 1) (< row 0)) 0)
> 	((= col 1) 1)
> 	((= col row) 1)
> 	(t (+ (pasc (- row 1) (- col 1)) (pasc (- row 1) col)))))
>
>

How about this?

(defun pascal (rows)
  (loop repeat rows for line = '(1)
    then (maplist #'(lambda (cons) (+ (first cons)
      (or (second cons) 0))) (cons 0 line))
    do (format t "~A~{~6D~}~%"
      (make-string (* 3 (- rows (length line)))
        :initial-element #\Space) line)))

Sorry about the indentation, it's really only supposed to be 4 lines
but this dang Google Groups message editor won't support the longer
lines (they're not THAT long!). The "~6D" and "(* 3" above allow the
function to display a properly formatted triangle up to 20 rows. If you
change "~6D" to handle displaying the bigger numbers required in more
rows than this, make sure to change the "(* 3" to half the width you
choose. This could probably be handled programatically, but the code
would be uglier.
From: Geoffrey Summerhayes
Subject: Re: is it effective/better
Date: 
Message-ID: <1155761503.332299.211460@b28g2000cwb.googlegroups.com>
John Stoneham wrote:
>
> How about this?
>
> (defun pascal (rows)
>   (loop repeat rows for line = '(1)
>     then (maplist #'(lambda (cons) (+ (first cons)
>       (or (second cons) 0))) (cons 0 line))
>     do (format t "~A~{~6D~}~%"
>       (make-string (* 3 (- rows (length line)))
>         :initial-element #\Space) line)))
>

 (format t "~&~VT~{~6D~}~%" (* 3 (- rows (length line))) line)

---
Geoff
From: John Stoneham
Subject: Re: is it effective/better
Date: 
Message-ID: <1155763289.232220.128290@74g2000cwt.googlegroups.com>
Geoffrey Summerhayes wrote:
>  (format t "~&~VT~{~6D~}~%" (* 3 (- rows (length line))) line)
>

Thanks, I've never been too great with format. However, I'm not sure
why but this version offsets the last row by one space, as opposed to
the version with make-string.
/goes digging into the format spec once again...
From: Geoffrey Summerhayes
Subject: Re: is it effective/better
Date: 
Message-ID: <1155763396.658569.56410@b28g2000cwb.googlegroups.com>
Geoffrey Summerhayes wrote:
> John Stoneham wrote:
> >
> > How about this?
> >
> > (defun pascal (rows)
> >   (loop repeat rows for line = '(1)
> >     then (maplist #'(lambda (cons) (+ (first cons)
> >       (or (second cons) 0))) (cons 0 line))
> >     do (format t "~A~{~6D~}~%"
> >       (make-string (* 3 (- rows (length line)))
> >         :initial-element #\Space) line)))
> >
>
>  (format t "~&~VT~{~6D~}~%" (* 3 (- rows (length line))) line)

*SIGH* just can't resist monkeying with code. Longer though :-(

(defun pascal (rows &optional (stream *standard-output*))
  (loop repeat rows
        for leading-spaces downfrom (* 3 (- rows 1)) by 3
        for line = '(1)
        then (maplist #'(lambda (cons)
                          (+ (first cons) (or (second cons) 0)))
                      (cons 0 line))
        do (format stream "~&~VT~{~6D~}~%" leading-spaces line)))

----
Geoff
From: prabuinet
Subject: Re: is it effective/better
Date: 
Message-ID: <1155818559.417893.185900@m79g2000cwm.googlegroups.com>
Geoffrey Summerhayes wrote:
> Geoffrey Summerhayes wrote:
> > John Stoneham wrote:
> > >
> > > How about this?
> > >
> > > (defun pascal (rows)
> > >   (loop repeat rows for line = '(1)
> > >     then (maplist #'(lambda (cons) (+ (first cons)
> > >       (or (second cons) 0))) (cons 0 line))
> > >     do (format t "~A~{~6D~}~%"
> > >       (make-string (* 3 (- rows (length line)))
> > >         :initial-element #\Space) line)))
> > >
> >
> >  (format t "~&~VT~{~6D~}~%" (* 3 (- rows (length line))) line)
>
> *SIGH* just can't resist monkeying with code. Longer though :-(
>
> (defun pascal (rows &optional (stream *standard-output*))
>   (loop repeat rows
>         for leading-spaces downfrom (* 3 (- rows 1)) by 3
>         for line = '(1)
>         then (maplist #'(lambda (cons)
>                           (+ (first cons) (or (second cons) 0)))
>                       (cons 0 line))
>         do (format stream "~&~VT~{~6D~}~%" leading-spaces line)))
>
> ----
> Geoff




I dont know how you people were able to think like this, I really
wonder how long you will be programming in LISP
From: Ken Tilton
Subject: Re: is it effective/better
Date: 
Message-ID: <9o0Fg.344$fE5.62@newsfe11.lga>
prabuinet wrote:
> Geoffrey Summerhayes wrote:
> 
>>Geoffrey Summerhayes wrote:
>>
>>>John Stoneham wrote:
>>>
>>>>How about this?
>>>>
>>>>(defun pascal (rows)
>>>>  (loop repeat rows for line = '(1)
>>>>    then (maplist #'(lambda (cons) (+ (first cons)
>>>>      (or (second cons) 0))) (cons 0 line))
>>>>    do (format t "~A~{~6D~}~%"
>>>>      (make-string (* 3 (- rows (length line)))
>>>>        :initial-element #\Space) line)))
>>>>
>>>
>>> (format t "~&~VT~{~6D~}~%" (* 3 (- rows (length line))) line)
>>
>>*SIGH* just can't resist monkeying with code. Longer though :-(
>>
>>(defun pascal (rows &optional (stream *standard-output*))
>>  (loop repeat rows
>>        for leading-spaces downfrom (* 3 (- rows 1)) by 3
>>        for line = '(1)
>>        then (maplist #'(lambda (cons)
>>                          (+ (first cons) (or (second cons) 0)))
>>                      (cons 0 line))
>>        do (format stream "~&~VT~{~6D~}~%" leading-spaces line)))
>>
>>----
>>Geoff
> 
> 
> 
> 
> 
> I dont know how you people were able to think like this,

I have the same feeling when I look at my own code. It does not spring 
whole from my mind, it evolves as I react to compiler errors, bugs, and 
unforeseen cases. Often in the end I look at the working result and only 
then see how it can be collapsed into more functional form to make it 
more maintainable and concise.

When I look at it a month or day later, having forgotten the process by 
which it arose, I wonder where it came from.

And in this case of Pascal's triangle, there is likely some "showing 
off" going on.

> I really
> wonder how long you will be programming in LISP
> 

having read your later clarification of this to mean "how long they have 
been programming in Lisp", there is that, too. :)

kt

-- 
Cells: http://common-lisp.net/project/cells/

"I'll say I'm losing my grip, and it feels terrific."
    -- Smiling husband to scowling wife, New Yorker cartoon
From: Rob Warnock
Subject: Re: is it effective/better
Date: 
Message-ID: <qqednXseQdJDxXjZnZ2dnUVZ_t6dnZ2d@speakeasy.net>
Ken Tilton <·········@gmail.com> wrote [in a different order]:
+---------------
| > I dont know how you people were able to think like this,
| 
| I have the same feeling when I look at my own code. ...
| When I look at it a month or day later, having forgotten the process
| by which it arose, I wonder where it came from.
+---------------

The same thing happens to me, but too often it's "I wonder
where the ·@·····@ this awful mess came from??!?!"  ;-}  ;-}

+---------------
| Often in the end I look at the working result and only then
| see how it can be collapsed into more functional form to make it 
| more maintainable and concise.
+---------------

In my experience, that getting-it-working-first and *then*
[possibly setting it aside for a while and then] re-reading it
is absolutely key to the creation of code which is elegant,
robust, and long-term maintainable. Without such re-reading
and "editing" [in the sense of editing a book for grammar
and style], the original hacks and misunderstanding remain,
and further hacks [as the code evolves] just pile up and the
code becomes less & less readable... and thus less & less
maintainable in the long run.

One of the "problems" of those higher-level languages [such
as Lisp!] which encourage correct programming the first time
is that this subsequent re-reading and editing never gets done.
C.f. "Warnock's Rule for Why BLISS Programs Are Big", circa 1971
or so [commonly voiced around the DECsystem-10 SIGIL meetings].
Hint: They tended to work the first time, so they didn't get
re-read (and thus didn't get re-written).


-Rob

-----
Rob Warnock			<····@rpw3.org>
627 26th Avenue			<URL:http://rpw3.org/>
San Mateo, CA 94403		(650)572-2607
From: Pierre THIERRY
Subject: Re: is it effective/better
Date: 
Message-ID: <pan.2006.08.17.12.52.39.424761@levallois.eu.org>
Le Thu, 17 Aug 2006 05:42:39 -0700, prabuinet a écrit :
> I dont know how you people were able to think like this, I really
> wonder how long you will be programming in LISP

Probably for my lifetime (and hopefully), as far as I'm concerned. The
fact that I'm my own boss and roll my own systems for my customers helps
a lot. (that is, my current customer won't ever see I've switched from
C++ to Lisp if I don't tell him, and doesn't care)

Happily,
Nowhere man
-- 
···········@levallois.eu.org
OpenPGP 0xD9D50D8A
From: prabuinet
Subject: Re: is it effective/better
Date: 
Message-ID: <1155821123.133140.106790@m79g2000cwm.googlegroups.com>
Pierre THIERRY wrote:
> Le Thu, 17 Aug 2006 05:42:39 -0700, prabuinet a écrit :
> > I dont know how you people were able to think like this, I really
> > wonder how long you will be programming in LISP
>
> Probably for my lifetime (and hopefully), as far as I'm concerned. The
> fact that I'm my own boss and roll my own systems for my customers helps
> a lot. (that is, my current customer won't ever see I've switched from
> C++ to Lisp if I don't tell him, and doesn't care)
>
> Happily,
> Nowhere man
> --
> ···········@levallois.eu.org
> OpenPGP 0xD9D50D8A

sorry, for my bad english, actually i tried to ask, how long u are
using lisp?
From: Pierre THIERRY
Subject: Re: is it effective/better
Date: 
Message-ID: <pan.2006.08.17.15.14.14.512330@levallois.eu.org>
Le Thu, 17 Aug 2006 06:25:23 -0700, prabuinet a écrit :
> sorry, for my bad english, actually i tried to ask, how long u are
> using lisp?

Two months, actually! ;-)

Recently,
Nowhere man
-- 
···········@levallois.eu.org
OpenPGP 0xD9D50D8A
From: Pascal Bourguignon
Subject: Re: is it effective/better
Date: 
Message-ID: <871wrgpoqh.fsf@thalassa.informatimago.com>
·········@gmail.com writes:

> i have just wrote a pascal's triangle program , since i'm a newbie to
> lisp, i dont know whether what i have written is an effective solution.
> can any one check this out... thankx in advance
>
>
> (defun pascal (rows)
>   (do ((i 1 (1+ i))) ((> i rows))
>     (do ((sp (- rows i) (1- sp))) ((= 0 sp)) (format t "  "))
>     (do ((j 1 (1+ j))) ((> j i))
>       (format t "~3a " (pasc i j)))
>     (format t "~%")))
>
>
> (defun pasc (row col)
>   (cond ((or (< col 1) (< row 0)) 0)
> 	((= col 1) 1)
> 	((= col row) 1)
> 	(t (+ (pasc (- row 1) (- col 1)) (pasc (- row 1) col)))))
>
>
> CL-USER> (pascal 12)
>                       1
>                     1   1
>                   1   2   1
>                 1   3   3   1
>               1   4   6   4   1
>             1   5   10  10  5   1
>           1   6   15  20  15  6   1
>         1   7   21  35  35  21  7   1
>       1   8   28  56  70  56  28  8   1
>     1   9   36  84  126 126 84  36  9   1
>   1   10  45  120 210 252 210 120 45  10  1
> 1   11  55  165 330 462 462 330 165 55  11  1

It gives the right results, doesn't it?  So it should be effective enough.


Now, one problem is that the width of the numbers is fixed.  My
solution adapts the width to the biggest number:

[18]> (print-pascal-triangle 14 :top-down-p t)

                                       
                                         1
                                      1     1
                                   1     2     1
                                1     3     3     1
                             1     4     6     4     1
                          1     5    10    10     5     1
                       1     6    15    20    15     6     1
                    1     7    21    35    35    21     7     1
                 1     8    28    56    70    56    28     8     1
              1     9    36    84   126   126    84    36     9     1
           1    10    45   120   210   252   210   120    45    10     1
        1    11    55   165   330   462   462   330   165    55    11     1
     1    12    66   220   495   792   924   792   495   220    66    12     1
NIL
[19]> (print-pascal-triangle 10 :top-down-p nil)
     1     1     1     1     1     1     1     1     1     1
     1     2     3     4     5     6     7     8     9    10
     1     3     6    10    15    21    28    36    45    55
     1     4    10    20    35    56    84   120   165   220
     1     5    15    35    70   126   210   330   495   715
     1     6    21    56   126   252   462   792  1287  2002
     1     7    28    84   210   462   924  1716  3003  5005
     1     8    36   120   330   792  1716  3432  6435 11440
     1     9    45   165   495  1287  3003  6435 12870 24310
     1    10    55   220   715  2002  5005 11440 24310 48620
NIL
[20]> 


(defun print-pascal-triangle (n &key top-down-p)
  "Prints Pascal's Triangle up to line n"
  (if top-down-p
      (loop
         with width = (ceiling (log (pascal n (truncate n 2)) 10))
         for line from 1 to n 
         do (loop
               initially (format t "~%~VA" 
                                 (truncate (* (/ (- n line) 2) (1+ width))) "")
               for column from 1 below line
               do (format t " ··@A" width (pascal (- line column) column)))
         finally (format t "~%"))
      (loop
         with width = (ceiling (log (pascal n n) 10))
         for i from 1 to n
         do (loop 
               for j from 1 to n
               do (format t " ··@A" width (pascal i j))
               finally (format t "~%")))))


Now, if you want to compute big triangles, or the pasc function for
big values, you'll have performance problems, since its complexity is
exponential.

One simple way to make it faster, is to memoize it:

(asdf:oos 'asdf:load-op :memoize)
(memoize:memoize-function 'pasc :key (function list) :test (function equal))


Another way to compute the triangle in polynomial time would be to do
it as we do it by hand, line by line.

(defun pascal-triangle (n)
  (loop
     :with row = (make-array n :adjustable t :fill-pointer 1 :initial-element 1)
     :for row-num :from 0 :below n
     :initially (print 1) (terpri)
     :do (loop :for p :across row :do (format t "~D " p))
     (loop :for i :from (- (length row) (if (oddp row-num) 2 1)) :downto 0
        :do (format t "~D " (aref row i)))
     (terpri)
     (when (evenp row-num)
       (vector-push-extend (aref row (1- (length row))) row))
     (loop :for i :from (1- (length row)) :downto 1
        :do (incf (aref row i) (aref row (1- i))))))

[41]> (with-open-stream (*standard-output* (make-broadcast-stream))
  (time (pascal-triangle 200)))
Real time: 1.112886 sec.
Run time: 1.108069 sec.
Space: 10211432 Bytes
GC: 12, GC time: 0.336022 sec.
NIL
[42]> 

But your function is much slower:

[40]> (with-open-stream (*standard-output* (make-broadcast-stream))
        (time (pascal 20)))
Real time: 10.341453 sec.
Run time: 9.932621 sec.
Space: 178080 Bytes
GC: 1, GC time: 0.028002 sec.
NIL


But after memoization, it becomes usable:

[45]> (asdf:oos 'asdf:load-op :memoize)
(memoize:memoize-function 'pasc :key (function list) :test (function equal))

;; Loading file /local/asdf-install/site/memoize-1.6/OBJ-CLISP-238-I686/memoize.fas ...
;; Loaded file /local/asdf-install/site/memoize-1.6/OBJ-CLISP-238-I686/memoize.fas
0 errors, 0 warnings
NIL
[46]> PASC
[47]> (with-open-stream (*standard-output* (make-broadcast-stream))
        (time (pascal 200)))
Real time: 2.702937 sec.
Run time: 2.55616 sec.
Space: 22407848 Bytes
GC: 23, GC time: 0.836054 sec.
NIL

-- 
__Pascal Bourguignon__                     http://www.informatimago.com/
Our enemies are innovative and resourceful, and so are we. They never
stop thinking about new ways to harm our country and our people, and
neither do we. -- Georges W. Bush
From: William James
Subject: Re: is it effective/better
Date: 
Message-ID: <1155921817.925421.324760@i3g2000cwc.googlegroups.com>
Pascal Bourguignon wrote:
> ·········@gmail.com writes:
>
> > i have just wrote a pascal's triangle program , since i'm a newbie to
> > lisp, i dont know whether what i have written is an effective solution.
> > can any one check this out... thankx in advance
> >
> >
> > (defun pascal (rows)
> >   (do ((i 1 (1+ i))) ((> i rows))
> >     (do ((sp (- rows i) (1- sp))) ((= 0 sp)) (format t "  "))
> >     (do ((j 1 (1+ j))) ((> j i))
> >       (format t "~3a " (pasc i j)))
> >     (format t "~%")))
> >
> >
> > (defun pasc (row col)
> >   (cond ((or (< col 1) (< row 0)) 0)
> > 	((= col 1) 1)
> > 	((= col row) 1)
> > 	(t (+ (pasc (- row 1) (- col 1)) (pasc (- row 1) col)))))
> >
> >
> > CL-USER> (pascal 12)
> >                       1
> >                     1   1
> >                   1   2   1
> >                 1   3   3   1
> >               1   4   6   4   1
> >             1   5   10  10  5   1
> >           1   6   15  20  15  6   1
> >         1   7   21  35  35  21  7   1
> >       1   8   28  56  70  56  28  8   1
> >     1   9   36  84  126 126 84  36  9   1
> >   1   10  45  120 210 252 210 120 45  10  1
> > 1   11  55  165 330 462 462 330 165 55  11  1
>
> It gives the right results, doesn't it?  So it should be effective enough.
>
>
> Now, one problem is that the width of the numbers is fixed.  My
> solution adapts the width to the biggest number:
>
> [18]> (print-pascal-triangle 14 :top-down-p t)
>
>
>                                          1
>                                       1     1
>                                    1     2     1
>                                 1     3     3     1
>                              1     4     6     4     1
>                           1     5    10    10     5     1
>                        1     6    15    20    15     6     1
>                     1     7    21    35    35    21     7     1
>                  1     8    28    56    70    56    28     8     1
>               1     9    36    84   126   126    84    36     9     1
>            1    10    45   120   210   252   210   120    45    10     1
>         1    11    55   165   330   462   462   330   165    55    11     1
>      1    12    66   220   495   792   924   792   495   220    66    12     1
> NIL
> [19]> (print-pascal-triangle 10 :top-down-p nil)
>      1     1     1     1     1     1     1     1     1     1
>      1     2     3     4     5     6     7     8     9    10
>      1     3     6    10    15    21    28    36    45    55
>      1     4    10    20    35    56    84   120   165   220
>      1     5    15    35    70   126   210   330   495   715
>      1     6    21    56   126   252   462   792  1287  2002
>      1     7    28    84   210   462   924  1716  3003  5005
>      1     8    36   120   330   792  1716  3432  6435 11440
>      1     9    45   165   495  1287  3003  6435 12870 24310
>      1    10    55   220   715  2002  5005 11440 24310 48620
> NIL
> [20]>
>
>
> (defun print-pascal-triangle (n &key top-down-p)
>   "Prints Pascal's Triangle up to line n"
>   (if top-down-p
>       (loop
>          with width = (ceiling (log (pascal n (truncate n 2)) 10))
>          for line from 1 to n
>          do (loop
>                initially (format t "~%~VA"
>                                  (truncate (* (/ (- n line) 2) (1+ width))) "")
>                for column from 1 below line
>                do (format t " ··@A" width (pascal (- line column) column)))
>          finally (format t "~%"))
>       (loop
>          with width = (ceiling (log (pascal n n) 10))
>          for i from 1 to n
>          do (loop
>                for j from 1 to n
>                do (format t " ··@A" width (pascal i j))
>                finally (format t "~%")))))
>
>
> Now, if you want to compute big triangles, or the pasc function for
> big values, you'll have performance problems, since its complexity is
> exponential.
>
> One simple way to make it faster, is to memoize it:
>
> (asdf:oos 'asdf:load-op :memoize)
> (memoize:memoize-function 'pasc :key (function list) :test (function equal))
>
>
> Another way to compute the triangle in polynomial time would be to do
> it as we do it by hand, line by line.
>
> (defun pascal-triangle (n)
>   (loop
>      :with row = (make-array n :adjustable t :fill-pointer 1 :initial-element 1)
>      :for row-num :from 0 :below n
>      :initially (print 1) (terpri)
>      :do (loop :for p :across row :do (format t "~D " p))
>      (loop :for i :from (- (length row) (if (oddp row-num) 2 1)) :downto 0
>         :do (format t "~D " (aref row i)))
>      (terpri)
>      (when (evenp row-num)
>        (vector-push-extend (aref row (1- (length row))) row))
>      (loop :for i :from (1- (length row)) :downto 1
>         :do (incf (aref row i) (aref row (1- i))))))
>
> [41]> (with-open-stream (*standard-output* (make-broadcast-stream))
>   (time (pascal-triangle 200)))
> Real time: 1.112886 sec.
> Run time: 1.108069 sec.
> Space: 10211432 Bytes
> GC: 12, GC time: 0.336022 sec.
> NIL
> [42]>

It's easier in a higher-level language, such as MatzLisp
(a.k.a. Ruby):

def pascal( rows )
  tr = Array.new(rows){|i| [1]*(i+1)}
  2.upto(rows-1){|i| prev = tr[i-1]
    1.upto(tr[i].size-2){|j| tr[i][j] = prev[j-1] + prev[j] }}
  wd = tr.last.map{|n| n.to_s.size}.max + 2 >> 1 << 1
  lnwd = tr.last.size * wd | 1
  puts tr.map{|row| row.map{|n|
    n.to_s.center(wd)}.join.strip.center(lnwd)}
end

pascal 11

                      1
                    1   1
                  1   2   1
                1   3   3   1
              1   4   6   4   1
            1   5   10  10  5   1
          1   6   15  20  15  6   1
        1   7   21  35  35  21  7   1
      1   8   28  56  70  56  28  8   1
    1   9   36  84 126 126  84  36  9   1
  1   10  45 120 210 252 210 120  45  10  1

And the Ruby version is faster than yours:

t = Time.now; pascal 200; STDERR.puts Time.now - t
0.235
From: Bill Atkins
Subject: Re: is it effective/better
Date: 
Message-ID: <1155924106.360825.210580@i42g2000cwa.googlegroups.com>
William James wrote:
> It's easier in a higher-level language, such as MatzLisp
> (a.k.a. Ruby):

Don't you ever get tired of being tiresome?