|
![](/i/fill.gif) |
Daniel Bastos escreveu:
> In article <web.4a8b9c8c606eeda4cb3dd3d0@news.povray.org>,
> nemesis wrote:
> By the way, I'm studying Scheme through PLT due to a clue from
> authority, which I gathered.
PLT is amazing, an excellent choice. I hope you also knows how to use
the combination keys for easily navigating/editing Lisp code:
alt+up/down to go up/down a parenthetical level, alt+left/right to go to
the next beginning or end, combine with shift to select and copy/paste
at will. Turns editing Lisp code a breeze and almost as good as with emacs.
> I absolutely know nothing about
> implementations,
Far too many to know. It's a minimalist language and several people for
several years tried their hands into making something unique, with
unique frameworks for it. Some of the bigger and best: PLT, Gambit,
Bigloo, Chez, SISC etc. In recent years, many excellent performant and
compliant with the latest language standard, R6RS, showed up: ikarus
and ypsilon come to mind.
> matter, but I already think about portability. Can you give me a word
> on portability?
Sure: many Scheme implementations are pretty portable. :)
Use what the implementation provides for system level access and you
should be fine.
> On UNIX, I use POSIX as a reference, even though I
Forget about low-level system access. Leave that to C.
> don't consider it a standard in a profound way; it works as a document
> to help me understand what is like to be common out there. I'd like
> that in Scheme.
>
>> #!r6rs
>> (import (rnrs base)(rnrs io simple)(rnrs programs))
>>
>> ; simple and straightforward standard R6RS scheme solution
>> (define (cat files)
>> (for-each
>> (lambda (file)
>> (call-with-input-file file
>> (lambda (port)
>> ; no simple line-oriented IO in standard R6RS
>> ; so you either write one or loop char-by-char
>> (let go ((c (read-char port)))
>> (if (not (eof-object? c))
>> (begin
>> (write-char c)
>> (go (read-char port))))))))
>> files))
>>
>> (cat (cdr (command-line)))
>
> I've kinda been able to read this; which is cool. But I don't really
> get the purpose of ``go'' here.
let creates lexical scopes. It's actually just a macro.
(let ((x 2)) (+ 1 x))
turns into:
((lambda (x) (+ 1 x)) 2)
(let label (bindings ...) ...) is called a named let. It turns the let
body into a full fleged local function of name label.
It's most immediate use is to create loops out of functions calls, since
as you know, there's no such builtin looping facility in functional
languages.
I could have defined an inner or outer function named go or whatever,
but simply used let. The normal let bindings turn into parameters with
initial values for the function. Thus,
(go (read-char port))
calls the function again. Beware that many people enjoy creating such
loops like (let loop (...) ...) but the label may be any of your choice.
Also, the body may sport several exits as stop condition.
There's no stack growing because of that last call, since the last call
is the call to the function itself. It's in tail position and suffers
an optimization called tail call elimination, which instead of actually
creating a new call stack, it replaces the current arguments with the
new arguments and goes to the first instruction again. It can do it
because it's in tail position, it's the last thing done in a function
body and it can be proved that no value other than the final value is
needed for the return of the function as whole. So, no need for a stack.
If the last call was something like (+ 1 (go ...)) than the call to go
would not be in tail position because some expression is expecting the
value it returns.
>> yes, I'm aware the C solution for this particular example would be way
>> shorter... :P
>
> I see it as the same thing; there isn't anything very high level about
> cat that could really be taken advantage of a very high level language.
>
> Here's the essence of cat from AT&T UNIX version 7.
>
> while (--argc > 0) {
> fi = stdin;
> while ((c = getc(fi)) != EOF)
> putchar(c);
> if (fi!=stdin)
> fclose(fi);
> }
that is the short essence without error handling. :)
> Hey, looking at this very old cat, I can see that Warp is going to say
> that our cats aren't cats after all; we don't read the stdin. And
> he'll be right.
Bah, just a matter of reorganizing a bit adding a short if before for-each:
(define (cat files)
(define (process port)
; no simple line-oriented IO in standard R6RS
; so you either write one or loop char-by-char
(let go ((c (read-char port)))
(if (not (eof-object? c))
(begin
(write-char c)
(go (read-char port))))))
(if (null? files) (process (current-input-port))
(for-each
(lambda (file) (call-with-input-file file process))
files)))
perhaps you should add (rnrs io ports) to the import list.
If you want to know more about Scheme:
http://www.r6rs.org/
http://schemers.org/
--
a game sig: http://tinyurl.com/d3rxz9
Post a reply to this message
|
![](/i/fill.gif) |