Whether you can do something with higher order functions or even simpler constructs isn't a great argument against having macros.

Recently I needed to do something for every string of length N or fewer. So I wrote a function that returned a closure that enumerated all strings until exhausting the string space. But I had to loop over the string space a few times in the program, and it got really cumbersome to write things like this:

(flet ((next-string (make-string-enumerator <num>))) (loop for str = (next-string) until (null str) do <body>))

Once I'd written that twice, I realized that I was eventually going to make mistakes writing or rewriting expressions like that, so I wrote a macro that expanded into that expression. Once I had the macro, I could write the following instead of the above:

(dostrings (str <num>) <body>)

Now, maybe you're thinking "That's only a two-line savings in any place where you'd need to do what you're doing", but to me the win is that the macro lets me write only the important things (the <body>, the maximum string length <num>), and the macroexpander takes care of the tedious and error-prone code for me. This isn't just saving typing: I don't have to think up a variable name like next-string whenever I need to loop over all strings, and so I never have to track down bugs introduced by changing variable names when refactoring. If I don't use it outside the macro, I don't even need to remember the purpose or interface for make-string-enumerator, either.

Yeah, I could have written something analogous to the <body> form as a function of the string returned by the enumerator, and written the original loop like this:

(let ((next-string (make-string-enumerator <num>))) (labels ((looper (body enumerator))) (let ((str (funcall enumerator))) (when str (funcall body str) (looper body enumerator)))))

But I'm not sure that's easier to understand than either the original loop form or the dostrings macro, and anyhow it's still long enough that I think I'd want something like my dostrings macro to generate it if I had to write something like that more than once.

Functions (including higher order functions and closures) are one way of factoring code for maintainability; macros are another. They complement each other.


In reply to Re^3: Overcoming addiction to Lisp by Anonymous Monk
in thread Overcoming addiction to Lisp by spurperl

Title:
Use:  <p> text here (a paragraph) </p>
and:  <code> code here </code>
to format your post, it's "PerlMonks-approved HTML":



  • Posts are HTML formatted. Put <p> </p> tags around your paragraphs. Put <code> </code> tags around your code and data!
  • Titles consisting of a single word are discouraged, and in most cases are disallowed outright.
  • Read Where should I post X? if you're not absolutely sure you're posting in the right place.
  • Please read these before you post! —
  • Posts may use any of the Perl Monks Approved HTML tags:
    a, abbr, b, big, blockquote, br, caption, center, col, colgroup, dd, del, details, div, dl, dt, em, font, h1, h2, h3, h4, h5, h6, hr, i, ins, li, ol, p, pre, readmore, small, span, spoiler, strike, strong, sub, summary, sup, table, tbody, td, tfoot, th, thead, tr, tt, u, ul, wbr
  • You may need to use entities for some characters, as follows. (Exception: Within code tags, you can put the characters literally.)
            For:     Use:
    & &amp;
    < &lt;
    > &gt;
    [ &#91;
    ] &#93;
  • Link using PerlMonks shortcuts! What shortcuts can I use for linking?
  • See Writeup Formatting Tips and other pages linked from there for more info.