Subject: Re: Can not find older posting: Reading files (fast)
From: rpw3@rpw3.org (Rob Warnock)
Date: Sun, 28 Aug 2005 05:00:34 -0500
Newsgroups: comp.lang.lisp
Message-ID: <ksydnTsoL9nfFozeRVn-sw@speakeasy.net>
Bernd Schmitt  <Bernd.Schmitt.News@gmx.net> wrote:
+---------------
| Rob Warnock wrote:
| > the following [from my "random utilities" junkbox] has linear
| > behavior in most CL implementations:
| > 
| >     (defun file-lines (path)
| >       "Sucks up an entire file from PATH into a list of freshly-allocated
| >       strings, returning two values: the list of strings and the number of
| >       lines read."
| >       (with-open-file (s path)
| > 	(loop for line = (read-line s nil nil)
| why is this indented like this?
+---------------

Well, it *wasn't*, when I posted it!  ;-}  ;-}

It was indented like this, with the LOOP indented two spaces inside
the WITH-OPEN-FILE (which was in turn two spaces inside the DEFUN):

    (defun file-lines (path)
      "Sucks up an entire file from PATH into a list of freshly-allocated
      strings, returning two values: the list of strings and the number of
      lines read."
      (with-open-file (s path)
        (loop for line = (read-line s nil nil)
              while line
          collect line into lines
          counting t into line-count
          finally (return (values lines line-count)))))

Customarily, the bodies of forms which define things or establish
bindings are indented two spaces in from the beginning of the enclosing
form. The above follows this for the bodies of DEFUN and WITH-OPEN-FILE.

LOOP indenting is slightly different, since it has a more COBOL-like
syntax which uses unevaluated symbols [but not necessarily from the
KEYWORD package!] as syntax markers or "LOOP keywords". In the above
LOOP, the syntax markers used are FOR, =, WHILE, COLLECT, INTO, COUNTING,
and FINALLY. [It is this non-Lispy embedded syntax that made me include
in my previous posting the caveat: "If you're willing to use a simple
LOOP without necessarily understanding it completely..."]

Opinions differ on proper style for LOOP indenting. A LOOP form may
contain binding/initializing/stepping sub-forms as well as "action"/
collecting/counting/summing/terminating sub-forms. Some people [and
the editors they use] like to indent the entire body of the LOOP by
five spaces, to line up with (typically) the first binding/initializing/
stepping sub-form, like this:

    (loop for line = (read-line s nil nil)
          while line
          collect line into lines
          counting t into line-count
          finally (return (values lines line-count)))

Others [yours truly among them] prefer to [and have configured their
editors to automate] indenting the binding/initializing/stepping
sub-forms five spaces, but then backing out to a two-space indent
for the "action"/collecting/counting/summing/terminating sub-forms,
like so:

    (loop for line = (read-line s nil nil)
          while line
      collect line into lines
      counting t into line-count
      finally (return (values lines line-count)))

This causes the indenting to resemble that of other binding and
iteration forms in the language.

Whatever style you choose, try to stick to it [though, where it
makes sense to do so, not slavishly] so the readers of your code
don't wonder why some of your code looks one way and some another.
[Otherwise, they may try to read meaning that isn't there into the
entrails of your LOOPs!]

+---------------
| > 	      while line
| > 	  collect line into lines
| > 	  counting t into line-count
| > 	  finally (return (values lines line-count)))))
| is this a kind of pseudo-code (otherwise i would miss some parens)?
+---------------

Yes, one might well say that!!  ;-}  ;-}

It is widely agreed by both those who love the Commonn Lisp LOOP
macro and those who hate it that LOOP is one of the *least* "Lispy"
parts of the CL standard -- it is truly an example of using a macro
to embed a different, application-specific language inside normal CL.
Nevertheless, it provides concise, powerful expressiveness for a
large percentage of the iteration tasks one runs into in practice.

Some resources for when you're ready to dig into it further:

  Tutorial:
    http://gigamonkeys.com/book/macros-standard-control-constructs.html
      [the section near the bottom called "The Mighty Loop"]
    http://gigamonkeys.com/book/loop-for-black-belts.html
      [the whole chapter]

  The Standard [well, the CLHS, based on the ANSI CL Standard]:
    http://www.lispworks.com/documentation/HyperSpec/Body/06_a.htm
      "6.1 The LOOP Facility"
    http://www.lispworks.com/documentation/HyperSpec/Body/06_aab.htm
      "6.1.1.2 Loop Keywords"
    http://www.lispworks.com/documentation/HyperSpec/Body/m_loop.htm
      "Macro LOOP"


-Rob

-----
Rob Warnock			<rpw3@rpw3.org>
627 26th Avenue			<URL:http://rpw3.org/>
San Mateo, CA 94403		(650)572-2607