Lennart, Fergus, 

re this stdin issue you're missing the point I was trying to make.  It
really only bites badly when you have concurrency.  I enclose the relevant
message, which gives an example of the extra expressiveness non-constant
stdin etc buys you -- I don't know which bit you disagree with, so the best
I can do is simply repeat it.

Simon

| > > I don't honestly see what having these handles as constant *gain* you,
| > > so why then have them as such, if not having them constant gives you
| > > extra expressiveness?
| > 
| > But, unless I'm missing something, making them non-constant doesn't
| > give you any extra expressiveness.
| > 
| > Remember that the fact they are constant does not imply that the
| > file they are connected to is constant.  Even if they are effectively
| > thread-local, i.e if the file that stdin and stdout are connected to
| > depends on which thread you're in, stdin and stdout themselves can
| > still be constants, can't they?
| Exactly!
| 
| I regard stdin, stdout, and stderr as names for abstract versions of
| 0, 1, and 2 (does my background in C programming on Unix show? :-).
| These are just handles, the can be reconnected to anything.  If you
| argue that you should be able to change the meaning of stdin I could
| argue "This piece of code I've got uses the constant 5, this is not
| what I want, I need to change the value of 5 locally when that code
| runs.  Give me the machinery to do that!"


To: [EMAIL PROTECTED] (Kevin Hammond)
cc: [EMAIL PROTECTED], simonpj
Subject: Re: stdin as a constant 
Date: Thu, 16 Jan 1997 11:07:19 -0800
From: Simon L Peyton Jones <simonpj>
Content-Type: text
Content-Length: 1859


| What you want is allowed.  Although stdin *is* a constant, it's simply a
| constant that refers to a handle.  The handle information (file pointer,
| attached device etc.) needn't be constant.  It's entirely consistent to
| provide, say:
| 
|         reconnect :: Handle -> Handle -> IO Handle
| 
| to connect one handle to the same device as another (as long as you're
| careful in the impl. about duplicating file pointers, which can get you into
| trouble -- new files are much easier to deal with!).  This was actually one
| of the extensions that was considered fairly carefully in the I/O design.

This doesn't do what Sigbjorn is suggesting.

Suppose I import a module written by someone else which exports
the function toUpper:

        -- toUpper reads stdin, converts all characters to upper
        -- case, and sends them to stdout
        toUpper :: IO ()

Now I import another module which exports sort:

        -- sort reads stdin, divides it into lines, sorts the lines
        -- and sends them to stdout
        sort :: IO ()

Now suppose I want to arrange to connect toUpper and sort together.
I might hope to do it like this:

        module Main where
        import M1( toUpper )
        import M2( sort )

        main = do 
                  (in,out) <- pipe;
                  forkIO (withStdOut in toUpper);
                  withStdIn out sort

The new functions are

        pipe :: IO (Handle,Handle)
        withStdOut, withStdIn :: Handle -> IO () -> IO ()

The point here is that toUpper and sort each work with *different* mappings
of stdin, stdout.


This example uses concurrency, which Haskell doesn't have.
In the absence of concurrency you can hack it like this:

        main = do 
                  (in,out) <- pipe;
                  old_stdout <- setStdOut in;
                  toUpper;
                  setStdOut old_stdout;
                  setStdIn out;
                  sort

But it's a hack, isn't it.  And it doesn't extend to concurrency.

But this may help explain why I'm not so steamed up as I am about argv!

Simon



Reply via email to