POV-Ray : Newsgroups : povray.off-topic : how to scheme a cat up? : Re: how to scheme a cat up? Server Time
5 Sep 2024 15:24:52 EDT (-0400)
  Re: how to scheme a cat up?  
From: nemesis
Date: 20 Aug 2009 14:14:50
Message: <4a8d929a@news.povray.org>
Daniel Bastos escreveu:
> In article <4a8c516d$1@news.povray.org>,
> nemesis wrote:
> Hm. In DrScheme? I'm not using it. I only use mzscheme and I write the
> code in anything. Usually on emacs.

Then you are well served anyway.

>> In recent years, many excellent performant and compliant with the
>> latest language standard, R6RS, showed up: ikarus and ypsilon come
>> to mind.
> 
> R6RS is sorta like POSIX or more sorta like ANSI C?

ANSI C, of course.  There are several POSIX in the Scheme world, it's 
the libs particular to a given implementation.

>>> Can you give me a word on portability?
>> Sure:  many Scheme implementations are pretty portable. :)
> 
> The implementation itself? I meant the scheme code itself. So that if
> I move from mz to $y scheme, then my code would still run. If there is
> a document saying which functions are likely to be common among
> certain implementations, then that could be my favorite subset of
> documentation. (I'll be reading the r6rs web document after posting
> this.)

R6RS is the latest standard, many implementations are using it already. 
  R5RS is more supported in some of the most robust out there, including 
Gambit and Bigloo.  R5RS is far less modular, there's only a single 
namespace.  Standard modules from R6RS are truly the single best 
addition to the language in a long time, though you could of course 
create ad hoc modules based solely on lexical scoping...

>>>> #!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.
> 
> So a lexical scope is a scope from the point of view of a macro? To a
> C programmer, the analogy would be scope of variables defined by a cpp
> macro?

No, nothing to do with macros, macros don't know about types or scope, 
just symbol substitution.

I suggest you read about scoping somewhere.  In C, there's only global 
scope, local scope and static scope per compilation unit.  Basically, 
lexical scope is the scope as it appears in the source text:  inner 
variables are only seen by inner functions, to find the value of a 
variable you just need to look it up in the chain of definitions as 
written in source code.  Like:

(let ((a 1))
   ; a seen here
   (let ((b 2))
     ; a and b seen here
     (+ a b))) ; -> 3

Lexical scoping as introduced by Algol comes into play once you 
understand how it was done before with dynamic scoping, like in elisp 
still today.  You could, for instance:

(define (foo) (+ 1 a))

(let ((a 2))
   (foo))

and it would work.  Fact is that it doesn't work under lexical (also 
called static) scoping because at the time of foo's definition, there's 
no variable a in scope.

BTW, if instead of let you use define a, it works.  define does not 
introduce lexical scope, it plainly modifies the global scope and, as 
you know, side effects are bad. ;)

>> (let ((x 2)) (+ 1 x))
>>
>> turns into:
>>
>> ((lambda (x) (+ 1 x)) 2)
> 
> That's instructive. There's probably a macro to expand macros? That be
> even more instructive.

Go easy on macros, it can be brain damaging... :)

but you can indeed call macros inside other macros.

>> (let label (bindings ...) ...) is called a named let.  It turns the let 
>> body into a full fleged local function of name label.
> 
> Interesting. So let can be used to also group statements, right? For
> example, (let () (+ 1 1) (* 3 4)). But what I have in mind is i/o,
> which is where a sequence of isolated statements makes more sense.

Those are not statements, those are expressions and only the value of 
the last one is returned from such a sequence.  But yes, you can use 
let.  It's exactly like the body of a function in that you can have a 
sequence of arbitrary expressions, still only the value of the last is 
returned.

> (let () (display "this ") 
>         (display "could help ") 
> 	(display "an imperative typa guy\n"))

yes, or begin, another macro.

>> 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.
> 
> Makes sense. When people are functional, they don't run in circles.

There's only functions and function calling.

> So (go) was a function, with an initial value in c. Cool. Now it makes
> perfect sense. Load another c, and continue.

yes, if it's not eof, then write the char and go again with another char. :)

>>   Also, the body may sport several exits as stop condition.
> 
> I'm yet to see how to break out of loops. I mean, recursion. That is,
> I'm yet to find out how to return earlier.

well, but I've shown you:  when it's eof, it stops.  It only further 
recurses if there's another char read.

(if (not (eof-object? c))
   ...
   (go (read-char port)))

> So if eof shows up, then the usual block of code does
> not run, and the last statement of the function runs which is its
> return statement. IOW, we never break out; we simply get faster to the
> end of the function. True?

You're still thinking about a C call stack here.  go is the last thing 
done in the body, it's in tail position and thus it's tail call 
optimized to remove call stacks.  It return imediatelly, there's no call 
stack rewinding because there's no stack growth.

But this example is essentially a loop for the purpose of side-effect 
only, it doesn't need a return value.  If you needed one, you could 
simply rework it a bit:

(if (eof-object? c) my-return-value
    else-expression)

> I don't think that's going to satisfy Warp, even though I just met
> her, or him. Because, although you appear to listen to the stdin if no
> files are given, a real cat would also pay attention to a file named
> -. :-) 

you could make it check if file is a "-" before calling process in the 
for-each loop and if it is, call (current-input-port).

BTW, perhaps you could use the comp.lang.scheme newsgroups to obtain 
more suited answers...

-- 
a game sig: http://tinyurl.com/d3rxz9


Post a reply to this message

Copyright 2003-2023 Persistence of Vision Raytracer Pty. Ltd.