s c h e m a t i c s : c o o k b o o k

/ FileManipulation / Cookbook.FileReadingLines

This Web


WebHome 
WebChanges 
TOC (with recipes)
NewRecipe 
WebTopicList 
WebStatistics 

Other Webs


Chicken
Cookbook
Erlang
Know
Main
Plugins
Sandbox
Scm
TWiki  

Schematics


Schematics Home
Sourceforge Page
SchemeWiki.org
Original Cookbook
RSS

Scheme Links


Schemers.org
Scheme FAQ
R5RS
SRFIs
Scheme Cross Reference
PLT Scheme SISC
Scheme48 SCM
MIT Scheme scsh
JScheme Kawa
Chicken Guile
Bigloo Tiny
Gambit LispMe
GaucheChez

Lambda the Ultimate
TWiki.org

Reading Lines from a Text File

PLT Scheme offers the read-line procedure for reading lines of text from an input port. The following are some useful procedures which use read-line to make it easy to process an entire file, one line at a time. This code was adapted from the comp.lang.scheme thread, How to read lines from a text file.

Simple iterative version

The following is a straightforward implementation which allows the programmer to provide a procedure which will be called with each new line read from a file.

(define (for-each-line-in-file filename proc . mode)
  (with-input-from-file
   filename
   (lambda () (apply for-each-line proc (current-input-port) mode))))

(define (for-each-line proc . port+mode)
  (let while ()
    (let ((line (apply read-line port+mode)))
      (unless (eof-object? line)
        (proc line)
        (while)))))

For documentation of the optional mode and port+mode parameters, see the PLT read-line documentation.

Example

The following will display the source code from the file ReadingLines.scm, with line numbers.

(for-each-line-in-file
  "ReadingLines.scm"
  (let ((line-num 0))
    (lambda (line) 
      (printf "~a: ~a ~n" line-num line)
      (set! line-num (add1 line-num)))))

Functional Version

In the above example, the line-num variable is mutated on each line. The design of for-each-line does not allow for state to be accumulated as reading progresses, so it is necessary to set up external state (using let in the above example) and mutate that state within the user-supplied procedure.

The standard functional programming idiom to deal with this situation is a fold, which is a functional generalization of iteration. Here are folding versions of the above functions:

(define (fold-lines-in-file filename proc init . mode)
  (with-input-from-file
   filename
   (lambda () (apply fold-lines proc init (current-input-port) mode))))

(define (fold-lines proc init . port+mode)
  (let while ((accum init))
    (let ((line (apply read-line port+mode)))
      (if (eof-object? line) accum
          (while (proc line accum))))))

Although these functions are similar in size and complexity to the previous versions, they are more powerful because they allow state to be passed from one invocation of the user-supplied procedure to the next.

Example

The above functions allow the previous example to be rewritten more simply, as follows:

(fold-lines-in-file
  "ReadingLinesWithFold.scm"
  (lambda (line line-num) 
    (printf "~a: ~a ~n" line-num line)
    (add1 line-num)) 
  1)

Notice that line numbering is achieved without needing to mutate a variable. The user-supplied procedure simply accepts a line-num argument, and when it's done, returns the next value for that argument. The initial line number is supplied as the last argument to fold-lines-in-file.

This general pattern is used by all fold operations, such as the canonical foldl function for folding over lists.

Contributors

-- AntonVanStraaten - 03 Apr 2004

See comp.lang.scheme thread for other contributors

Comments

Source code is in: ReadingLines, ReadingLinesSample, ReadingLinesWithFold, ReadingLinesWithFoldSample

CookbookForm
TopicType: Recipe
ParentTopic: FileRecipes
TopicOrder:

 
 
Copyright © 2004 by the contributing authors. All material on the Schematics Cookbook web site is the property of the contributing authors.
The copyright for certain compilations of material taken from this website is held by the SchematicsEditorsGroup - see ContributorAgreement & LGPL.
Other than such compilations, this material can be redistributed and/or modified under the terms of the GNU Lesser General Public License (LGPL), version 2.1, as published by the Free Software Foundation.
Ideas, requests, problems regarding Schematics Cookbook? Send feedback.
/ You are Main.guest