Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

How to read lines from a text file?

34 views
Skip to first unread message

Stuart Brorson

unread,
Mar 5, 2003, 7:30:52 PM3/5/03
to
Greetings, Schemers,

I would like to use Scheme to read the contents of a text file --
hopefully line by line -- and dump them into an output file. Doing
this is very easy in a procedural language like Perl. There, I just
need to do something like:

#! perl -w
while($Line = <INPUTFILE>) {
printf OUTPUTFILE ("Line = $Line \n");
}

Unfortunately, I am having lots of problems doing this in Scheme. I
cannot get the iteration structures ("let" and "do") to work for me,
and I get all kinds of crazy errors when I try to do it recursively
(e.g. ERROR: Wrong type to apply: #<unspecified>).

Can somebody please translate the above line of Perl into Scheme? I
have already opened the file and all that stuff; I just need to
iterate and read a single line on each iteration. The single line
needs to be available for processing and output. Note that I do need
to sense the EOF condition (using eof-object?) before reading a line
so that I can continue with the program after the EOF.

Thanks in advance for your help!

Stuart

Jens Axel Søgaard

unread,
Mar 5, 2003, 7:43:37 PM3/5/03
to
Stuart Brorson wrote:
> I would like to use Scheme to read the contents of a text file --
> hopefully line by line -- and dump them into an output file.

I'm busy right now, so I will just give you the link to

http://www.htus.org/Book/2001-11-13/howto-Z-H-5.html#%_sec_3

but perhaps you should start at the beginning:

http://www.htus.org/Book/2001-11-13/howto-Z-H-3.html#%_part_I

Note that let is a binding construct and not an iteration construction.

And...
http://www.scsh.net/cgi-bin/wiki.cgi?FileToStringList
which features

; file->string-list : string -> list-of-strings
; read lines from the file filename, return them in a list
(define (file->string-list filename)
(let ((port (open-input-file filename)))
(let lp ((all-lines '()))
(let ((line-or-eof (read-line port)))
(if (eof-object? line-or-eof)
(reverse! all-lines)
(lp (cons line-or-eof all-lines)))))))


--
Jens Axel Søgaard


Jussi Piitulainen

unread,
Mar 6, 2003, 2:52:32 AM3/6/03
to
Jens Axel Søgaard writes:

> Note that let is a binding construct and not an iteration
> construction.

True, but in R5RS "named let" is in section 4.2.4 Iteration.
--
Jussi

David Rush

unread,
Mar 6, 2003, 7:48:34 AM3/6/03
to
Stuart Brorson <s...@cloud9.net> writes:
> #! perl -w
ick.

> while($Line = <INPUTFILE>) {
> printf OUTPUTFILE ("Line = $Line \n");
> }

untested equivalent:

(let while ((line (read-line (current-input-port))))
(if (not (eof-object? line))
(begin
(write `(line ,line) (current-output-port)) (newline (current-output-port))
(while (read-line (current-input-port))))
))

david rush
--
In no other country in the world is the love of property keener or
more alert than in the United States, and nowhere else does the
majority display less inclination toward doctrines which in any way
threaten the way property is owned.
-- Democracy in America (Alexis de Tocqueville)

Jens Axel Søgaard

unread,
Mar 6, 2003, 10:03:11 AM3/6/03
to

Makes sense, but it wasn't where I expected to find it.

--
Jens Axel Søgaard


Scott G. Miller

unread,
Mar 6, 2003, 10:22:35 AM3/6/03
to
David Rush wrote:
> Stuart Brorson <s...@cloud9.net> writes:
>
>>#! perl -w
>
> ick.
>
>
>>while($Line = <INPUTFILE>) {
>> printf OUTPUTFILE ("Line = $Line \n");
>>}
>
>
> untested equivalent:
>
> (let while ((line (read-line (current-input-port))))
> (if (not (eof-object? line))
> (begin
> (write `(line ,line) (current-output-port)) (newline (current-output-port))
> (while (read-line (current-input-port))))
> ))
>

How about this, to eliminate my pet-peeve of named-lets and do in this
situation, which is the need to use the read-expression twice (the name
'while' may be improved):

(define-syntax while
(syntax-rules ()
((_ ((?loop-var ?loop-test ?loop-val-expr) ...) ?expr* ...)
(let loop ((?loop-var ?loop-val-expr) ...)
(if (and ?loop-test ...)
(begin ?expr* ...
(loop ?loop-val-expr ...)))))))


Which allows us to write (using SRFI-28):

(while ((line (not (eof-object? line))
(read-line (current-input-port))))
(display (format "Line = ~a~%" line)))


Scott

Dorai Sitaram

unread,
Mar 6, 2003, 11:48:23 AM3/6/03
to
In article <v6epuod...@corp.supernews.com>,
Scott G. Miller <scgm...@freenetproject.org> wrote:

>David Rush wrote:
>>
>> (let while ((line (read-line (current-input-port))))
>> (if (not (eof-object? line))
>> (begin
>> (write `(line ,line) (current-output-port)) (newline (current-output-port))
>> (while (read-line (current-input-port))))
>> ))
>>
>
>How about this, to eliminate my pet-peeve of named-lets and do in this
>situation, which is the need to use the read-expression twice (the name
>'while' may be improved):
>
>(define-syntax while
> (syntax-rules ()
> ((_ ((?loop-var ?loop-test ?loop-val-expr) ...) ?expr* ...)
> (let loop ((?loop-var ?loop-val-expr) ...)
> (if (and ?loop-test ...)
> (begin ?expr* ...
> (loop ?loop-val-expr ...)))))))
>
>
>Which allows us to write (using SRFI-28):
>
>(while ((line (not (eof-object? line))
> (read-line (current-input-port))))
> (display (format "Line = ~a~%" line)))

It's enough to have the named-let take no arguments to avoid
the text duplication.

(let while ()
(let ((line (read-line))) ;<-- only one occurrence of
; (read-line)


(if (not (eof-object? line))
(begin

(write `(line ,line)) (newline)
(while)))))

Stuart Brorson

unread,
Mar 6, 2003, 1:09:37 PM3/6/03
to

Greetings again --

Thanks to everybody who answered my plea for help. The posts from both
Jens and David were very helpful. As it turns out, I adopted David's
code. Since I like to share solutions to solved problems, here's my
code:


;;----------------------------------------------------------
;; Given a filename, open the file, get the contents, and dump them
;; into the spice file.
;; Calling form is "(insert-text-file input-file output-file)"
;; The function opens input-file, but assumes that output-file is
;; already open.
;;
;; This function is usually used to include spice models contained in
;; files into the netlist. Note that it doesn't
;; check the correctness of the spice code in the file.
;;----------------------------------------------------------
(define insert-text-file
(lambda (model-filename port)
(let ((model-file (open-input-file model-filename)) )
(let while ((model-line (read-line model-file)))
(if (not (eof-object? model-line))
(begin
(display (string-append model-line "\n") port)
(while (read-line model-file))
) ;; end of inner begin
) ;; end of if
) ;; end of inner let
(close-port model-file)
) ;; end of outer let
)
)

I have run it in my application; it works like a champ!

Thanks again -- you guys have been a real help to a Scheme newbie!

Stuart

David Rush

unread,
Mar 6, 2003, 4:43:31 PM3/6/03
to
Stuart Brorson <s...@cloud9.net> writes:
> Thanks to everybody who answered my plea for help. The posts from both
> Jens and David were very helpful. As it turns out, I adopted David's
> code.

Eek! I was just trying to mirror the structure used in the Perl
example. FWIW, Here's a way that you might (or might not) want
to make a terser (and richer) text-file copy...

> (define insert-text-file
> (lambda (model-filename port)

...


> (close-port model-file)
> ) ;; end of outer let
> )

(define (text-file-copy-from model-filename port)
(with-input-from-file model-filename
(lambda ()
(let while ((line (read-line)))
(if (not (eof-object? line))
...)))
))

the point being that the with-* and call-with-* procedures from R5RS
are really lovely for processing the whole file in a single scope. Not
that it's hugely different from what you've adopted, but it's an idiom
that is very typical of the Scheme approach to solving most problems:
first-class functions. You get some free functionality (in this case
file-handle management) wrapped around your code - without *any*
macros or other wacky hacks (I'm thinking of Tcl's `upvar' here).

Just a suggestion, in case you're trying to redirect your thinking
from Perl mode.

david rush
--
I do not weep at the world --- I am too busy sharpening my oyster knife
-- Zora Neale Hurston

Anton van Straaten

unread,
Mar 6, 2003, 5:09:01 PM3/6/03
to
Dorai Sitaram wrote:

> It's enough to have the named-let take no arguments to avoid
> the text duplication.
>
> (let while ()
> (let ((line (read-line))) ;<-- only one occurrence of
> ; (read-line)
> (if (not (eof-object? line))
> (begin
> (write `(line ,line)) (newline)
> (while)))))

Neat! But no fair using a hybrid looping/binding construct as a pure
looping construct! :)

Although it's obvious enough, I can't resist wrapping that in a nice general
function:

(define (for-each-line proc)


(let while ()
(let ((line (read-line)))

(if (not (eof-object? line))
(begin

(proc line)
(while))))))

So we can get all high-level about it, and stop Perl from getting too
uppity:

(for-each-line
(lambda (line) (write `(line ,line)) (newline)))

--Anton

P.S. We might also want something like:

(define (for-each-line-in-file filename proc)
(with-input-from-file
filename
(lambda () (for-each-line proc))))

0 new messages