From: Dan Weinreb
Subject: Replies
Date: 
Message-ID: <fa922de4-447d-4611-9019-237122bf3342@v39g2000pro.googlegroups.com>
blandest: That's nice and short.  In the Olde Days, we would have
criticized the storage allocation done by the concatentation, but
these days it's not a big deal.  I wish Common Lisp had a more
succinct way to do (concatenate 'string ...).  You neglected to turn
the strings into integers but that's trivial.

Russ Lonstein: Excellent, provided you use the split-sequence library
as discussed.

Ranier Joswig: Using a reader macro that does a side-effect at
newline is novel; I would not have thought of that.

Xah Lee: Elisp is an interesting choice.  But without converting the
strings to integers, it's not really right.

It's interesting that Elisp already has a style of reading in the
whole file, but no built-in to convert strings to integers, whereas
Common Lisp is the other way around.

The statement "It is not so mostly because emacs people have drawn
themselves into a elitist corner, closing off to the outside world" is
just a rude ad hominem attack.

Your claim that this shows something wrong with lists is completely
unclear, although if I read your paper (I'll try) I might have some
idea what you're getting at

Andre Thieme: There's no reason to be insulting.  First of all, who
says the file was stored by a Lisp program?  Lisp should be able to
read and parse anything.  Second, if you are interested in Lisp, we
should be welcoming new users, not insulting them.  The best way for
Lisp to become more acceptable is for there to be more users.

Ken Livingston: I think use of the readtable is more straightforward
than what Ranier did.  And remembering that read-delimited-list exists
is great; I think we all forgot about that.

Stylistically, it's a bit strange to use the stream as a special
returned value.  I do understand that you're using the stream as an
object that can't possibly be the outcome of read-delimited-list, but
I personally am not a fan of special return values.  Also, the
exception handling can use handler-case instead of handler-bind, which
is simpler and less code.  Sadly, Common Lisp does not define the
condition that is signaled upon end of file.  And the filename ought
to be an argument, not a global.  Maybe something like this?

(defun read-lines (filename)
  (with-open-file (stream filename)
    (loop for item = (handler-case
			 (read-delimited-list #\newline stream)
		       (t () (return-from read-lines result)))
	  collect item into result)))

Now, suppose we wanted to do it the way the Ruby code does it.  Assume
we have a built-in function called read-lines that takes a filename,
opens the file, reads all the way to the end, and returns one string
for each line.

(mapcar (lambda (line)
	  (mapcar #'parse-integer (split-sequence:split-sequence line)))
	(read-lines "blob.txt"))

Ruby has shorter names than Lisp.  If we compensate for that, just to
narrow down where the differences are:

(mapcar (lambda (line)
	  (mapcar #'to-i (split line)))
	(readlines "blob.txt"))

We can make it look more like Ruby by reversing the order of arguments
to mapcar and writing it all on one line.  First add function "mp",
which is map with its arguments reversed.

(defun mp (list function) (mapcar function list))

Now, here's how the Common Lisp looks next to the Ruby:

(mp (readlines "blob.txt") (lambda (line) (mp (split line) #'to-i)))
IO.readlines("blob.txt").map{|line| line.split.map{|s| s.to_i }}

These are pretty similar.  So Lisp is missing read-lines, has longer
names, and takes the arguments to the mapping function backwards from
that of Ruby.  Also, Ruby's "to_i" is probably a generic, less elegant
to implement in Common Lisp because not everything is an instance of a
class.

The reason Lisp mapping functions take the function first is so that
they can provide many lists, if the function takes more than one
argument.  I don't know how this is handled in Ruby.

Note that these issues are specific to Common Lisp.  Another dialect
of Lisp could have the above changes and still be faithful to Lisp.

From: K Livingston
Subject: Re: Replies
Date: 
Message-ID: <147362e4-712c-431e-8808-ea9fee5f0dcc@q30g2000prq.googlegroups.com>
On Jan 19, 2:40 pm, Dan Weinreb <····@alum.mit.edu> wrote:
> Stylistically, it's a bit strange to use the stream as a special
> returned value.
...
> I personally am not a fan of special return values.

I dislike special values too.  I get really annoyed when someone
returns a sentinel to mean failure/false, because then a ton of useful
lisp operations are broken (some, any, and, or, ...) ...exactly as I
just did in this example, *sigh*.  I didn't really want to make the
handler-case the problem of the caller, but I guess now that I think
about either the caller uses a handler-case or checks for a sentinel,
and I agree, the sentinel is not the functional way to go.

> I do understand that you're using the stream as an
> object that can't possibly be the outcome of read-delimited-list, but
> I personally am not a fan of special return values.

Re: "can't possibly..."
Although returning the stream is a relatively common approach, I
realized not too long ago, that while unlikely, the stream object
*could* actually be returned.  Reader macros have access to the
stream, and could, should they choose for some bizarre reason, return
it.  If you really wanted something completely free of this problem, I
think you'd have to go with something like a fresh cons cell.  (I
think someone else wrote a post or article on that not too long
ago.)

Anyone who likes torturing programs can just stick something like this
in their input:
#.(set-macro-character #\\Space #'(lambda (stream char) stream))

Not that that won't muck up your input enough anyway (unless that's
what you want), and not that there aren't infinitely more evil things
to do with unchecked input and or #. but just as a point - the stream
can get out.

Kevin
From: Carl Taylor
Subject: Re: Replies
Date: 
Message-ID: <SY8dl.144056$_Y1.59757@bgtnsc05-news.ops.worldnet.att.net>
K Livingston wrote:
> On Jan 19, 2:40 pm, Dan Weinreb <····@alum.mit.edu> wrote:
>> Stylistically, it's a bit strange to use the stream as a special
>> returned value.
> ...
>> I personally am not a fan of special return values.
>
> I dislike special values too.  I get really annoyed when someone
> returns a sentinel to mean failure/false, because then a ton of useful
> lisp operations are broken (some, any, and, or, ...) ...exactly as I
> just did in this example, *sigh*.  I didn't really want to make the
> handler-case the problem of the caller, but I guess now that I think
> about either the caller uses a handler-case or checks for a sentinel,
> and I agree, the sentinel is not the functional way to go.
>

Why not use IGNORE_ERRORS which will return NIL as a primary value when 
a condition is raised?

(defun make-file-line-list (path)
  (let ((*readtable* (copy-readtable)))
     (set-syntax-from-char #\Newline #\) )
     (with-open-file (stream path :direction :input)
        (loop for data = (ignore-errors (read-delimited-list #\Newline 
stream))
                unless data do (loop-finish)
                collect data))))


clt