![](/i/fill.gif) |
![](/i/fill.gif) |
|
![](/i/fill.gif) |
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |
Invisible wrote:
> Apparently POSIX only specifies the -u option; the rest is extensions.
> (Common ones though, apparently.) This is apparantly typical for all
> widely-known Unix commands. I guess we can thank 40,000,000 years of
> backwards compatibility for that.
And back then, primitive humans really enjoyed watching the monkeys work
the abacuses while a cat command was being executed. Or was that
primitive humans really enjoyed watching the monkeys execute a cat?
I can't remember. That was a long time ago ;)
--
~Mike
Post a reply to this message
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |
In article <4a8b7a38@news.povray.org>,
Daniel Bastos wrote:
> This cat does not handle exceptions. I might see how that works next.
Looks like this suffices.
(define (sigint v)
(fprintf (current-error-port) "^C\n"))
;main
(with-handlers ([exn:break? (lambda (v) (sigint v))])
(cat (vector->list (current-command-line-arguments))))
It's interesting that I need to (exit) from sigint. What if I would
like to ignore that signal, or continue somehow? No idea what to do.
Hey, if you're very curious, there's some information in v. :-)
Post a reply to this message
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |
In article <web.4a8b9c8c606eeda4cb3dd3d0@news.povray.org>,
nemesis wrote:
> Daniel Bastos <dbastos+0### [at] toledo com> wrote:
>> #!/usr/bin/env mzscheme
>> (module cat scheme/base
>>
>> (define (interact f)
>> (let ([ln (read-line)])
>> (cond
>> [(not (eq? ln eof))
>> (and
>> (printf "~a\n" (f ln))
>> (interact f))])))
>>
>> (define (id x) x)
>>
>> (define (cat files)
>> (for-each
>> (lambda (x)
>> (with-input-from-file x
>> (lambda ()
>> (interact id))))
>> files))
>>
>> ;main
>> (cat (vector->list (current-command-line-arguments)))
>> )
>>
>> With with-input-from-file, we get the stdin connected to the file
>> opened, so no changes in interact were required.
>
> That's the PLT way. here's another:
By the way, I'm studying Scheme through PLT due to a clue from
authority, which I gathered. I absolutely know nothing about
implementations, but I saw this guy who seems to do his homework using
PLT, so instead of MIT, I picked PLT. Clearly at this point it doesn't
matter, but I already think about portability. Can you give me a word
on portability? On UNIX, I use POSIX as a reference, even though I
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.
>> Lisp likes might be hackestables.
>
> I just love Lisp, Scheme in particular. Minimalist like C, only much higher
> level. Incidentally, the only two languages I truly enjoy, for different
> purposes sure.
Same here.
> 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) {
if (fflg || (*++argv)[0]=='-' && (*argv)[1]=='\0')
fi = stdin;
else {
if ((fi = fopen(*argv, "r")) == NULL) {
fprintf(stderr, "cat: can't open %s\n", *argv);
continue;
}
}
fstat(fileno(fi), &statb);
if (statb.st_dev==dev && statb.st_ino==ino) {
fprintf(stderr, "cat: input %s is output\n",
fflg?"-": *argv);
fclose(fi);
continue;
}
while ((c = getc(fi)) != EOF)
putchar(c);
if (fi!=stdin)
fclose(fi);
}
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.
Post a reply to this message
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |
In article <4a8bba80$1@news.povray.org>,
Invisible wrote:
> Warp wrote:
>
>> 'cat' is a program for concatenating files. It's used like:
>>
>> cat file1 file2 file3 > concatenated_files
>>
>> Your program does not fulfill this role.
>>
>> (Some people abuse 'cat' to concatenate one single file with nothing,
>> but that doesn't mean that the role of 'cat' is anything else than
>> concatenating files.)
>
> Interesting. I thought it was for concatenating a file to stdout...
It is. :-) In the same order in which they are read.
> Alrighty then:
>
> import System.Environment
>
> main = do
> args <- getArgs
> mapM_ (\arg -> readFile arg >>= putStr) args
>
> That seems to work.
>
> I'm guessing the real cat program also has assorted command-line
> switches as well though?
Your cat has a disease, common in recently seen cats, the makes it
ignore the stdin.
Post a reply to this message
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |
In article <4a8bf5a7$1@news.povray.org>,
Invisible wrote:
> Apparently POSIX only specifies the -u option; the rest is extensions.
> (Common ones though, apparently.) This is apparantly typical for all
> widely-known Unix commands. I guess we can thank 40,000,000 years of
> backwards compatibility for that.
I can't even say -u is really necessary.
> The attached program appears to do the job. There are probably still
> some bugs in it though.
That program is no cat. That's Garfield.
Post a reply to this message
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/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) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |
Invisible <voi### [at] dev null> wrote:
> The attached program appears to do the job.
I think you have way too much time on your hands... :P
--
- Warp
Post a reply to this message
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |
Warp wrote:
> Invisible <voi### [at] dev null> wrote:
>> The attached program appears to do the job.
>
> I think you have way too much time on your hands... :P
You *think*?!
I thought we already settled this one, many years ago. ;-)
Besides, it's not a very long program, and I haven't actually tested it
properly. (As you probably know, testing typically takes a really long
time.)
Post a reply to this message
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |
In article <4a8c516d$1@news.povray.org>,
nemesis wrote:
> 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.
Hm. In DrScheme? I'm not using it. I only use mzscheme and I write the
code in anything. Usually on emacs.
> 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?
>> 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.)
>> On UNIX, I use POSIX as a reference, even though I
>
> Forget about low-level system access. Leave that to C.
I meant it as an analogy. When I'm working directly with UNIX, then
POSIX is a good document. Not to be followed, I say, but to be
noticed.
>>> #!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?
> (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.
> (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.
(let () (display "this ")
(display "could help ")
(display "an imperative typa guy\n"))
> 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.
> 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.
So (go) was a function, with an initial value in c. Cool. Now it makes
perfect sense. Load another c, and continue.
> 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. That appears to be simply
to protect the region of code that would run in case whe need not
return earlier. 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?
>> 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)))
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
-. :-)
Changing subject. It is ugly to assign functionality to file names,
but it is much more likely, I say, that we will eventually need to
read a couple files plus the stdin, than to name a file as -.
Post a reply to this message
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |
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
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |
|
![](/i/fill.gif) |
| ![](/i/fill.gif) |
|
![](/i/fill.gif) |