I sometimes write programs in Perl for my research and I would greatly
like to learn to use Scheme (after having read about it), but I am
stuck at the very beginning with practical problem solving issues.
I would greatly appreciate a help.
I would like to be able to write in the Scheme the kind of script that
I most often find myself writing in Perl, but I lack an appropriate
example. My typical Perl program of this kind opens an ascii file
containing some tables (variable length fields, evidently not S-
expressions), reads it, stores it in memory as an array, one string
for each line; them splits each line at blank spaces (and/or commas)
and, if a certain equality condition is met, it assigns each so-
obtained substring to a sub-array.
Then it loops through the so-obtained nested array to print some of
the sub-arrays' elements to an output file.
I include in the following lines an example of rudimentary perl script
executing the described operations.
I would be very grateful if someone could send me a link to the source
of a simple Scheme program doing the sort of things I described.
Thank you very much in advance.
Best regards
Gian Luca Brunetti
Dipartimento BEST, Politecnico di Milano
_________________________________
sub write_a_new_file()
{
my $infile = "/some_address";
my $outfile = "/some_other_address";
open( INFILE, "$infile" );
open( OUTFILE, ">$outfile" );
my @lines = <INFILE>;
close(INFILE);
my $counter = 0;
foreach my $line (@lines)
{
{
my @row = split( /\s+/, $line );
if ( $row[0] eq "pattern_to_match" )
{
push( @lines_to_write, [ $row[1], $row[2], $row[3] ] );
}
}
$counter = $counter++;
}
foreach $line_to_write (@lines_to_write)
{
print OUTFILE "${$line_to_write}[0], ${$line_to_write}[1], ${$vertex}
[2]\n";
}
}
#lang racket
(define infile "C:\\tmp\\in.txt")
(define outfile "C:\\tmp\\out.txt")
(define lines (file->lines infile #:mode 'text #:line-mode 'linefeed))
(define lines-to-write (filter (λ (line) (regexp-match #rx"^foo"
line)) lines))
(with-output-to-file outfile (λ () (for-each (λ (line) (printf "~a~n"
line)) lines-to-write)) #:mode 'text #:exists 'append)
Thank you very much for the answer. It thoroughly satisfies my
practical needs, but it stirs up one more question by me, due to sheer
curiosity.
I see that the function fine->lines is implementation-dependent (#lang
racket) and takes something like keywords a la Common Lisp (like with-
output-to-file), which also is implementation-dependent.
I wonder if someone has to point me to a non-implementation dependent
solution, maybe r4rs or r5rs, even if much longer.
Thank you again, in advance.
> Thank you very much for the answer.
Here's a variant that is somewhat closer to your code (splits on
whitespace, outputs commas, and drops the first word):
#lang racket
(define infile "./some_address")
(define outfile "./some_other_address")
(define lines (map (λ (s) (regexp-split #px"\\s+" s))
(file->lines infile)))
(define lines-to-write
(for/list ([line (in-list lines)]
#:when (equal? (car line) "pattern_to_match"))
(string-join (cdr line) ", ")))
(display-lines-to-file lines-to-write outfile)
> It thoroughly satisfies my practical needs, but it stirs up one more
> question by me, due to sheer curiosity.
>
> I see that the function fine->lines is implementation-dependent
> (#lang racket) and takes something like keywords a la Common Lisp
> (like with- output-to-file), which also is implementation-dependent.
The keywords were not really needed for a direct translation of your
code, but yes -- the whole thing is very racket-dependant.
> I wonder if someone has to point me to a non-implementation dependent
> solution, maybe r4rs or r5rs, even if much longer.
You can try sticking to more common functionality (like using
`read-line' repeatedly, since it's a bit more common), maybe dig
through some SRFIs etc. But if you're coming from a practical point
of view, you'd better choose an implementation and use what it has to
offer. (A complete code isn't hard to write for this, you just have
to dump some conveniences like regexps, and reading lines. New
practical needs will get you even more stuck.)
--
((lambda (x) (x x)) (lambda (x) (x x))) Eli Barzilay:
http://barzilay.org/ Maze is Life!
Thank you very much for the answer. I find it very, very useful.
I think I understand the advantages of using the racket-dependant
functions "for/list" and "in-list" and I see the advantages of
sticking with an implementation.
I guess that my wish to be able to solve my basic practical problems
in Scheme using just a small set of primitives (plus regexes) stems
from an intellectual - even if maybe not entirely rational - need. Due
to which I would still find very useful finding some repositories or
examples featuring small, complete, and best if elemetary-style-
written programs performing the kind of described operations.
I would be very grateful if someone could point me to them, if
existing.
I think this would greatly enhance my understanding of the language.
Thank you again, in advance and in any case.
Have you looked at Scheme shell, scsh?
Thank you for the suggestion: scsh is really very intesting and the
site has very useful examples.
I was just trying not to bet on specific implementations before I have
learned how to use the very basics of the language; and I think that
to do that I would most of all benefit from reading very simple,
little, non-implementation-dependent practical scripts.
In a sense, I am trying to figure out what I have to learn in
programming, and I would like very much that it turns to be Scheme.
One unmentionable reason for this is that I think id that heavily
indented Scheme code looks insanely great. One more serious reason is
that I think that operations on list suit my brain.
At cognitive level, I am heavily invested in fields other than
programming (building technology) and for a number of reasons I feel
that if I don't manage to use Scheme as soon as possible, this may
never happen. I'd not mind to end up writing in a child-like Scheme
for a while or even forever, provided that I very soon put myself in
the position of being capable to write some working code.
> I wonder if someone has to point me to a non-implementation dependent
> solution, maybe r4rs or r5rs, even if much longer.
R6RS provides read-line, and that is very common among implementations.
There is also IrRegex which is an R5RS regular expression engine, which
should do the job just fine as well.
In R6RS, you might do something like this to get the lines from a file:
(define (file->lines path)
(call-with-input-file path
(lambda (if)
(let loop ([lines '()])
(let ([line (read-line if)])
(if (eof-object? line)
(reverse lines)
(loop (cons line lines))))))))
Aaron W. Hsu
--
Programming is just another word for the lost Art of Thinking.
Thank very much for the script.
It is wonderful to look into the procedure "file->lines".
At first I didn't understand the first "let" construct, then I seached
through documentations and I saw that it is a named let.
I am starting to grasp that using this definition of "file-lines",
using "for-each" and "cond" instead of "for/list" and #:when, and
avoiding the use of the function "in-list", I could possibly manage to
modify the interesting solution kindly posted by Eli Barzillay in an
equivalent one implementation-independent, even if less efficient.
Thank you again.
I see one issue with your approach: if my Perl doesn't fail me you read
in the whole input file into memory, then determine which lines to print
and finally print them. This can have dramatic effects if the input
file is large. Memory wise an approach where you only act on one line
at a time is more efficient.
Not to spoil the fun (and sorry for posting Ruby code in a Scheme forum)
but here is how that single line approach would look like in Ruby:
File.open "/some_other_address", 'w' do |out|
File.foreach "/some_address" do |line|
row = line.split /\s+/
out.puts(row[0..2].join(', ')) if row[0] == "pattern_to_match"
end
end
For a regexp match you would do something like this
out.puts(row[0..2].join(', ')) if /rx/ =~ row[0]
In case you need to correlate information from different lines to
determine what to print this approach doesn't work of course.
Kind regards
robert
Thank you for the observation.
The Ruby code is very short.
However, in this case, it is better for me to load the file content in
one whole data structure, to be able to modify it afterwards in
various ways.