Hacker News new | past | comments | ask | show | jobs | submit login
Q about Exercise 10.4 in "ANSI Common Lisp"
7 points by paul_reiners on March 22, 2008 | hide | past | favorite | 10 comments
I came up with the following solution for Exercise 4 in Chapter 10 of "ANSI Common Lisp" by Paul Graham:

  (defmacro ntimes (n &rest body)
    (let ((h (gensym)))
      `(let ((,h ,n))
         (if (> ,h 0)
            ,@body)
         (if (zerop ,h)
             nil
             (ntimes (1- ,h) ,@body)))))
Using GNU CLISP 2.44, this works fine. However, when I use SBCL 1.0.6 via Cusp v0.8.174 and do the following call:

  (ntimes 10
          (princ "."))
I get the following error:

Control stack exhausted (no more space for function call frames). This is probably due to heavily nested or infinitely recursive function calls, or a tail call that SBCL cannot or has not optimized away.

What exactly is going on here? Is my solution correct and SBCL is wrong, or is my solution incorrect but it just happens to work on CLISP?




You've written a recursive macro. That is usually a mistake. Here (unless you mean the first argument always to be a constant) you're recursing based on values that won't be available till runtime, yet the macro could be expanded at compile-time.

You should just expand into a do.


I guess I'm not understanding the problem then, because I thought we were not supposed to expand into a do, since the problem states:

"Define ntimes (page 167) to expand into a (local) recursive function instead of a do."

Isn't the problem asking you to write this without expanding into a do, or am I missing something here? What would be a correct solution to the problem?


Oops, didn't read the problem. Yes, as other commenters say, you should expand into a call to a recursive function, not an expression that gets expanded recursively.

If you were writing this for real you'd expand into a do, so this problem is somewhat artificially difficult.


> Oops, didn't read the problem.

You wrote the problem. ;)


Thanks, I figured it out now.


My Lisp-fu is lower than the expected for this exercice. But it seems that you have to create a recursive function not a recursive macro, which is what you are doing.

Maybe the macro has to define a new recursive function that recurses until need, and then call it?


Yes, I believe local functions are usually defined with flet.


I'm not sure, but I think you need to use labels, rather than flet, in this case, since local functions defined using flet cannot be recursive. At least that's how I interpret what it says on page 319.

At any rate, this solution works using labels:

  (defmacro ntimes (n &rest body)
      (let ((h (gensym))
            (g (gensym)))
        `(let ((,h ,n))
           (labels ((ntimes-local (,g) 
                    (if (> ,g 0) 
                        ,@body)
                    (if (zerop ,g)
                        nil
                        (ntimes-local (1- ,g)))))
             (ntimes-local ,h)))))
(Sorry, but again I don't know how to preserve the formatting of my code in this newsgroup.)



Sorry about the non-pretty printing. It was nicely formatted, when I entered it (I swear). Is there something like a <code> tag I could use?

Also, not all of the error message printed. What's up with that?




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: