Re: Making argv a constant

1997-01-20 Thread Frank Christoph

  Holy cow!  It's been a long time since I've had my mailbox packed with
letters from the Haskell list.  Just when I was beginning to wonder if there
were still other people writing Haskell programs... :)

 | First, Simon, I think you're a little biased on this issue.  I'm sure that
 | making argv a global constant would be a practical benefit for programs
 | like GHC.

 You're probably right.  I am certainly biased towards large programs.  But I
 really want Haskell to scale to large programs, rather than become
 unreasonably inconvenient to use when the program becomes big.

  Well, I don't want to make a federal case out of this issue, but I what I
had in mind when I made the above statement was the fact that so many "real"
applications these days use a GUI as a front-end.  These kinds of programs
typically *don't* accept a large number of command line arguments; instead
they read in parameters from an initialization file.  I would almost go so far
as to call the CLI (command line interace) archaic, except that it resembles a
function call so much.  :) It's still a fact, though, that even in FL
programming we avoid functions with a very large number of arguments, and
monads are one convenient way around this.

  I'm not contesting the idea that the way argv is handled in Haskell
currently is inadequate.  But I am saying that the simple solution of making
argv a global constant is not good FL style, for reasons I and others have
already mentioned.  When you write a function that takes a large number of
arguments, do you usually solve it by making all the arguments global??  In
Haskell, I think, the preferred approach is to break the function into a
small set of combinators which can be composed instead.

  In a sense, this is a moot point here because conventional OSes impose this
kind of CLI "bottleneck", and it only goes to show how out of place FL
languages are in such a context.

 | nooks and crannies of a program.  Most applications are not nearly so |
 configurable,

 I disagree!  Most "real" programs (i.e. products) are highly configurable.

  Well, re: configurability, I still think a compiler is in another dimension
altogether, but even for other highly configurable applications, it is now
considered questionable practice to parametrize them at the command-line for
several reasons:

  1. it's ugly and difficult to understand for beginners
  2. it encourages the birth of many, unnecessarily dissimilar throw-away
 languages with questionable syntax (consider sed, tr, grep, etc.)
  3. it is often insufficiently expressive (see #2)
  4. it fixes statically

  Hence, it is usually much better in "real" applications to provide a way to
set parameters internally, for example by means of an "Options" menu, etc.

[Note: Many of you will insist that programs like sed and tr are so useful
precisely because of the flexibility of their CLI.  I don't disagree with
that; I'm just saying that there is some "unnecessary diversity" -- to quote
the Haskell Report.]

 | Third, I could say that choosing to use a functional language is in some
 | sense also accepting the fact that you are "forced to accept some benefits"
 | which you could do without.

 I don't agree.  In exchange for the costs of higher-order functions, or
 laziness, or the lack of side effects, I get some benefits.  In exchange for
 making argv accessible only via an IO action I get nothing at all.

  But you do, and you've admitted it yourself!  You get more modularity, 
flexibility and maintainability, like for example the ability to parametrize
your program with several sources of input, or input from a file rather than
the command line.

  Besides, the point here is not whether we perform an IO action or not.  In
fact, I would argue that argv has to do with IO indirectly, in that it
provides string values that can be mapped to input files (for instance).  The
point is, for me at least, the scoping.  By this reasoning, we might just as
well revert to the "main :: [String] - String" model, though, which I think
is inadequate.

  Since I've gone this far, I might as well explain why I find the whole
global argv idea so outright distasteful.  Simon keeps talking about Real
World Applications, so I might as well lay it on the table here and now.

  Frankly, I don't give a damn about GUI interfaces, options menus or argument
plumbing.  My gut reaction to global argv is that it is bad because it
encourages writing monolithic applications, rather than communicating
processes.  The current trend in the Real World now is component-oriented:
things like OpenDoc, ActiveX and CORBA, where programs are small and
dynamically configurable.  In this sense, the old, honored Unix tradition of
combinator-like, map- and filter-like programs is still alive and well, and
in some ways Haskell is in a great position to capitalize on it.

  Making it easy to read and farm out arguments from a command line packed
with unrelated options is as sure a ticket to the 

Subunits (was: Re: Making argv a constant)

1997-01-20 Thread Jim Hassett

Sverker Nilsson wrote:

In Ada they have structured a similar kind of code inclusion with
something called "subunits".
. . .
body_stub ::=
 subprogram_specification IS SEPARATE
|PACKAGE BODY package_simple_name IS SEPARATE;
|TASK BODY task_simple_name IS SEPARATE;

subunit ::=
SEPARATE (parent_unit_name) proper_body

[End Quote]

Also using the package syntax from Ada (to avoid the risk of
overloading the Haskell Module Concept excessively) a direct
translation of the compiler example to use these subunit directives
(without semicolons ;-) would be:

[omitted details of example using proposed Haskell subunits]

In Ada, they separate specification and implementation of packages.  I
think this is partly for information hiding purposes and partly to
help the compiler to separate-compile efficiently.  I have only used
the package body part in this example, assuming the specifications be
generated in some magic way. But I actually think that also Haskell
could take advantage of separation of specification and implementation.

Body stubs work in Ada because there is always a full specification
of the stubbed unit visible at the position of the body stub, so that
the compiler has all the information it needs to handle any subsequent
references to the stubbed unit.  (For packages and tasks, there must
be a full specification preceding the body stub, while for subprograms,
the specification is part of the body stub.)  It is not necessary for
the compiler to read the proper body while it is compiling the parent
unit, as the proper body provides only implementation details.

On the other hand, the parent unit (with its body stubs) must be
compiled before the subunit, so that the compiler has access to the
declarations in the parent that are to be made visible to the subunit.

A corresponding mechanism in Haskell would likewise require separate
specification (or interface) and implementation for each subunit.
The specification would either need to be part of the body stub, or
appear as some kind of prior declaration visible at the position of
the body stub.  I'm not familiar enough with Haskell modules to say
whether they could be readily adapted to this purpose.

- Jim Hassett







Re: Making argv a constant

1997-01-18 Thread Fergus Henderson

Simon L Peyton Jones, you wrote:
 
 Fergus
 
 | I would find Simon's arguments more convincing if he showed
 | a convenient idiom that did things properly, rather than a
 | convenient way to write broken programs.
 | 
 | (Doing it properly is probably not too hard, but I'll leave it up to
 | the proponents of this proposal to demonstrate this...)
 
 It's hard for me to respond to this since I don't know what you have in mind
 when you say "properly".  If you mean proper error reporting, then that's
 not difficult:
 
   main = checkArgForErrors argv   
  rest of prog...

[aside: presumably you can drop the argv parameter, since you want
argv to be a constant, right?]

 I'm not sure what else you had in mind.

Just that, together with Joe Fasel's suggestions, plus putting
the argument-parsing stuff in an exception monad, and defining
`checkArgForErrors' to check whether the option structure is
`Fail message'.

One difference between doing it "properly" and doing it the
way you suggested in your original post is that doing it properly
is significantly more complex.  This alters the trade-offs a bit.

(Sorry if I've been a bit pedantic -- see my .sig ;-)

P.S.  Is this list archived anywhere?

--
Fergus Henderson [EMAIL PROTECTED]   |  "I have always known that the pursuit
WWW: http://www.cs.mu.oz.au/~fjh   |  of excellence is a lethal habit"
PGP: finger [EMAIL PROTECTED] | -- the last words of T. S. Garp.






Re: Making argv a constant

1997-01-18 Thread Fergus Henderson

Sigbjorn Finne, you wrote:
 
 OK, so stdin is not a global constant anymore, but is stashed away in
 TLS somewhere.

No! stdin _is_ a global constant.
What is stashed away in TLS is the binding of stdin to whichever
file it happens to be bound to.  Of course if your thread implementation
doesn't have TLS as such, you can put this binding in the thread-local
IO state.  (Your thread implementation *must* have this, if redirecting
stdin for a thread can be implemented at all.)

 I don't like this at all, for the following reasons:

Your implementation-related arguments are all bogus.

[...]
 But, the standard handles can be made thread-local, just provide
 access to them through IO! A straightforward implementation
 of IO in a multi-threaded setting might be
 
  type Triple a = (a,a,a)
  newtype IO a = IO (Triple Handle - _RealWorld - (_RealWorld, a))
 
 Creating new processes (using Concurrent Haskell's forkIO, say) can
 then easily be augmented to functionally change the interpretation of
 the standard handles for a process. This solution is simple, modular
 and does not require TLS or other RTS Magic.

... and works fine if `stdin', `stdout', and `stderr' are constants!

 I'm only arguing that make the standard handles be connected to IO,
 which is the only context they can *ever* be used.

The fact that the standard handles can only ever be used in conjunction
with an IO is exactly why they can be constant.  Think of the
constant value as an index into your triple in IO.

-- 
Fergus Henderson [EMAIL PROTECTED]   |  "I have always known that the pursuit
WWW: http://www.cs.mu.oz.au/~fjh   |  of excellence is a lethal habit"
PGP: finger [EMAIL PROTECTED] | -- the last words of T. S. Garp.






Re: Making argv a constant

1997-01-18 Thread Fergus Henderson

Sigbjorn Finne, you wrote:
 
 ... the issue here is *not* how you configure your programs, there's more
 than one way to do that (to paraphrase the Perl slogan), but the fact that
 argv is *constant* and should be provided as such. I've yet to see a
 post contending that argv isn't.

I pointed out that although argv is constant over any single program
execution, it variables from execution to execution, so it's not
really constant.

Note that there are existing functional language implemenations, in
particular Gofer, that assume that constants are really constant, not
just constant over each program execution.

For example, the following Gofer program

x = 42
y = x + x
main = appendChan stdout (show y) abort done

requires fewer reductions when you run it the second time around,
because `y' has already been evaluated.

The behaviour of Hugs is different in this respect (why? was it
changed to support hacks such as `argv = unsafePerformIO getArgs'?).
It appears that in Hugs, CAFs are reset whenever you get back
to the command prompt; evaluating `y' twice gives you the
same number of reductions in both cases.

Requiring the Hugs behaviour could (a) make implementing Haskell slightly
more difficult and (b) reduce efficiency, for interpreters and JIT
compilers.

-- 
Fergus Henderson [EMAIL PROTECTED]   |  "I have always known that the pursuit
WWW: http://www.cs.mu.oz.au/~fjh   |  of excellence is a lethal habit"
PGP: finger [EMAIL PROTECTED] | -- the last words of T. S. Garp.






Re: Making argv a constant

1997-01-18 Thread Lennart Augustsson


 I would claim it has really nothing to do with first-class modules
 or parameterized modules. They can be simulated by ordinary Haskell
 data types with named fields.
No they can not.  Haskell records do not allow local polymorphism,
so you have a significant loss of power.

-- Lennart






Re: Making argv a constant

1997-01-18 Thread Sigbjorn Finne

Lennart Augustsson [EMAIL PROTECTED] writes:
 
 ...
 Can't we agree on a name and make it one of the "commonly
 implemented extensions" to Haskell?  That way I can still
 feel that Haskell is pure, but if you feel the urge to use
 it you can still do it.  I'd actually prefer the performOnceBeforeMain
 solution if someone can come up with some simple restrictions
 to make it work.
 

I think this is a good compromise, leave System.getArgs as it is
and have a new extension module called SystemExt (?) that would
contain constants for argv and the environment (and leave room for
growth for other System overflow). If it turns out that at
some future crossroads for the Haskell libraries, argv is so
commonly used, then move it to System. I'm happy with that.

I haven't thought through `performOnceBeforeMain' and its
implications.

--Sigbjorn






Re: Making argv a constant

1997-01-18 Thread Sigbjorn Finne

Fergus Henderson [EMAIL PROTECTED] writes:
 
 I pointed out that although argv is constant over any single program
 execution, it variables from execution to execution, so it's not
 really constant.
 

It is constant within the lexical scope of an executing program;
that's constant enough for me, your mileage may vary.

 ...
 The behaviour of Hugs is different in this respect (why? was it
 changed to support hacks such as `argv = unsafePerformIO getArgs'?).
 It appears that in Hugs, CAFs are reset whenever you get back
 to the command prompt; evaluating `y' twice gives you the
 same number of reductions in both cases.
 

Nothing nefarious, I'm afraid. The change from Gofer to Hugs was done
to avoid residual CAF garbage building up (the simplest way of implementing
CAF GC - I think Nottingham and Yale are discussing how to do this
properly).

Re: argv in a command-line interpreter, it is not obvious why you want to
change argv from within an eval prompt - to configure the invocation of
Hugs, yes, but not to set the command-line options for later evaluations.
(last time I looked, Hugs had System.getArgs defined to always return [])
The latest beta release of Yale Hugs support the use of it as a
command-line tool, i.e., a silent option causes it to suppress all
interpreter
output, reading just expressions to evaluate from stdin and output their
results on stdout. Perhaps the command shell is a more appropriate
place from where to change argv?

--Sigbjorn






Re: Making argv a constant

1997-01-17 Thread Sverker Nilsson

Simon L Peyton Jones wrote:

 The point is, if I *want* to have several behaviours in one run I can
 always use this second technique.  But Haskell as it now stands prevents
 me from using the first, even when I *don't* want several behaviours in one
 run.  I'd be prepared to pay the pain if I wanted the benefit.  Since I
 don't want the "benefit" I don't want the pain.  
 

That seems fair enough. Actually I have wanted to do things the first
way myself sometimes with other constant things than the environment,
but then I have just thought that that's not possible in principle, in
Haskell.

I see this environment stuff like a special case of some more general
problem. There are other constants that one might like to have as
constants in the program. For example, the date and time the program
started is also a constant and could reasonably be accessed as such.
(It could be in the environment, but in general it has to be read
into the program in some other way.)

So if it turns out to be possible to make the environment a constant,
it should open up possibilities for other constants as well. I
would rather see a general mechanism. Something like:

performOnceBeforeMain:: IO a - a

timeStarted = performOnceBeforeMain (getCurrentTime)

Just like that one would do with unsafePerformIO, but with
safer semantics (hopefully) and blessed by Standard Haskell.

Then we wouldn't even need to change the environment to constant.
And we would have the benefit of having access to any other things
that are constant as well.

 This message has clarified that there are three (not two) reasons
 that argv should be constant
 
   1.  Easier programming
   2.  Faster running
   3.  Extra reasoning ability (this the new one; every call to
   f will behave the same way)
 

The only real problem I can think of right now, is that this -
I would really like to call it this paradigm shift - could complicate
implementation of persistent storage systems. But I feel quite
fuzzy about that anyway right now, so...

Sverker






Re: Making argv a constant

1997-01-17 Thread Rick Morgan


  The point is, if I *want* to have several behaviours in one run I can always
  use this second technique.  But Haskell as it now stands prevents me from
  using the first, even when I *don't* want several behaviours in one run.
  I'd be prepared to pay the pain if I wanted the benefit.  Since I don't want
  the "benefit" I don't want the pain.
 
   First, Simon, I think you're a little biased on this issue.  I'm sure that
 making argv a global constant would be a practical benefit for programs like
 GHC, but a compiler is a very specialized application, and exactly the sort
 that takes a huge number of arguments and then threads them to all the little
 nooks and crannies of a program.  Most applications are not nearly so
 configurable, and I think there is considerably less burden on the programmer
 when it comes to distributing argument values.
 

I think Simon's bias is towards big systems. The LOLITA Natural Language
Processing system which the group here is working on is 54k lines of Haskell
and we have experience exactly the same kinds of problem that Simon mentions.

Also, Sverker Nilsson wrote: 

 performOnceBeforeMain:: IO a - a

 timeStarted = performOnceBeforeMain (getCurrentTime)
 
 Just like that one would do with unsafePerformIO, but with
 safer semantics (hopefully) and blessed by Standard Haskell.

This doesn't look very safe to me if performOnceBeforeMain get's called
more than once.

Rick






Re: Making argv a constant

1997-01-17 Thread Sverker Nilsson

   timeStarted = performOnceBeforeMain (getCurrentTime)
   
   Just like that one would do with unsafePerformIO, but with
   safer semantics (hopefully) and blessed by Standard Haskell.
 
 I see some serious problems:
 
   a = (performOnceBeforeMain m1,performOnceBeforeMain m2)
 
 In which order are m1 and m2 performed?
 

Don't know. Maybe it could be acceptable to define it to be
nondeterministic, like for the relative interleaving of the branches
of forkIO. (Which isn't standard Haskell either...)

 
   f x = performOnceBeforeMain x
 
 What does this mean?
 

Don't know. Maybe it means a run-time error: I'd think that the system
could detect that there is an occurence of performOnceBeforeMain that
was not possible to reduce before Main started.

 Even if we only allow performOnceBeforeMain in declarations of the form
 
name = performOnceBeforeMain expr
 

Yes, this seems to be a safer form.

 in which order should such declarations be performed?
 
  

How about only allowing one call to performOnceBeforeMain in your
program? It may be a little awkward from a software-engineering
point but...

module Constants where
(options, startTime, addressBook, etc) = performOnceBeforeMain expr

I don't see these problems as more serious than the very concept
of making things from the environment, in general, available as
constants in your program.

If we could have the Environment variables as constants, and can solve
the semantic difficulties associated with that, and the other problems
that might occur, then I think we should amortize this work on a
general mechanism.

So that you could for example have a constant look-up table array
available, read from a file of several megabytes.  (Impossible to pass
in the Environment, unless you make some really radical changes to
some system-defined constants, in the Unix Kernel I think.)

(Personally, _I_ would like to get at least that benefit for the work
that I think I will have to do to redesign my Haskell persistency
library almost from scratch, which would be needed if we made the
Environment constant :-)

Sverker






Re: Making argv a constant

1997-01-17 Thread Joe Fasel

I think Fergus's efficiency argument may be a red herring.
Here is an excerpt from a compiler I wrote recently:

 data JvlArgs = JvlArgs {optNoLink :: Bool,
 optVerbose :: Bool,
 jvlClassNames :: [String]}
 deriving Show
  
 jvlArgs :: JvlArgs
 jvlArgs = getJvlArgs (unsafePerformIO getArgs)
  JvlArgs {optNoLink = False,
   optVerbose = False}
  
 getJvlArgs :: [String] - JvlArgs - JvlArgs
 getJvlArgs ("-c":ss) args = getJvlArgs ss (args {optNoLink = True})
 getJvlArgs ("-v":ss) args = getJvlArgs ss (args {optVerbose = True})
 getJvlArgs (s@('-':_):_) _ = error ("bad option: " ++ s)
 getJvlArgs ss args = args {jvlClassNames = map internalClassName ss}

Note that argv (= unsafePerformIO getArgs) is a constant (as is
jvlArgs), defaults are dealt with systematically, error handling
(not very extensive in this case) is done, and the arguments are
scanned only once (lazily, in fact).

Cheers,
--Joe

Fergus Henderson wrote:
| Simon L Peyton Jones wrote:
|  
|  I agree with Sigbjorn about argv, rather strongly, though apparently nobody
|  else does.
|
| No, I agree Sigbjorn's proposal is probably a good idea, although I don't
| feel strongly either way.  (I was just disagreeing with the reasoning that
| he used to motivate it.)
|
|  module CmdLineOpts where
|  
|  argv = unsafePerformIO getArgs
|  
|  unfoldSize :: Int
|  unfoldSize = lookupInt "-funfold-size" argv
|  
|  useCleverFiniteMap :: Bool
|  useCleverFiniteMap = lookup "-fclever" argv
|
| I have a comment, and couple of questions.
|
| First, this will involve scanning argv once for each possible option;
| I guess option handling is not likely to be a bottleneck, but still...
| this offends some aesthetic sense of mine.
|
| Second, how do you handle syntax errors in the command line arguments?
| What does lookupInt do if the integer overflows, or if the argument
| is not valid syntax for an integer?  Do you check for misspelt or
| invalid option names?
|
|  PS. I'm less steamed up about the stdin issue; but I think you missed
|  Sigbjorn's point.  Yes stdin is a constant now, but he'd like stdin *not* to
|  be a constant, so that he could take a value of type IO () that used stdin,
|  and reconnect its stdin to (say) a file.
|
| Even if stdin remains a constant, you could still do that, because even
| if the handle is a constant, the connection between handle and file can
| still vary, just as the file contents can vary.
|
| -- 
| Fergus Henderson [EMAIL PROTECTED]   |  "I have always known that the pursuit
| WWW: http://www.cs.mu.oz.au/~fjh   |  of excellence is a lethal habit"
| PGP: finger [EMAIL PROTECTED] | -- the last words of T. S. Garp.
|

Joseph H. Fasel, Ph.D.  email:  [EMAIL PROTECTED]
Technology Modeling and Analysisphone:  +1 505 667 7158
University of Californiafax:+1 505 667 2960
Los Alamos National Laboratory  postal: TSA-7 MS F609
Los Alamos, NM  87545






Re: Making argv a constant

1997-01-17 Thread David J. King


 P.S.  Is this list archived anywhere?

Not at the moment.  But I'm planning on making messages available
on the web.  I have all the posts since I started moderating the
list back in October, and I can probably get hold of stuff before
that.

Cheers,

David.
-- 
David J. King   Email:  [EMAIL PROTECTED]
Department of Computing Science Phone:  +44 (0)141 339 8855 ext 8335
University of Glasgow   Fax:+44 (0)141 330 4913
Glasgow  G12 8QQURL:http://www.dcs.gla.ac.uk/~gnik







Re: Making argv a constant

1997-01-17 Thread Joe Fasel

Fergus,

Quite right.  I used "error" because I was lazy.

In fact, the lazy evaluation of the arguments is also a red herring,
because the compiler is in fact strict in argv.  (How else does it
know what to compile?)  All the flag arguments must be scanned
in order to retrieve "jvlClassNames jvlArgs".

I suppose that a better way to do this is something like this:

 getJvlArgs :: [String] - JvlArgs - Either JvlArgs String

 processedArgs :: Either JvlArgs String
 processedArgs = getJvlArgs argv JvlArgs {optNoLink = False,
  optVerbose = False}

 jvlArgs :: JvlArgs
 jvlArgs = case processedArgs of
  Left args - args
  Right msg - error ("mishandled arguments: " ++ msg) 

Then the main IO monad of the compiler can check processedArgs
once when it picks up the list of class names and proceed with
compilation or yield an IO error.  This scheme still avoids plumbing
jvlArgs through the rest of the compiler.

But I'm a lazy programmer.  ;-)

At this point, I may be leaning more toward Lennart's position,
as I'm less convinced of how valuable the "convenience" is.

--Joe

Fergus Henderson wrote,
| I'm still not entirely happy with the error handling, though.
| As a general rule, I try to use `error' only for internal software
| errors, not for error messages that can result from the user's
| mistakes.  (But perhaps that is another functional programmer's
| death wish... what do other people think about this issue?)
|
| Also, the fact that the arguments are scanned lazily is in fact
| slightly worrying -- I hope your program is guaranteed to always
| evaluate jvlArgs, since I don't think it would be a good idea to ignore
| syntax errors in the command-line options just because you don't happen
| to execute a part of the program that needs to examine them.

Joseph H. Fasel, Ph.D.  email:  [EMAIL PROTECTED]
Technology Modeling and Analysisphone:  +1 505 667 7158
University of Californiafax:+1 505 667 2960
Los Alamos National Laboratory  postal: TSA-7 MS F609
Los Alamos, NM  87545






Re: Making argv a constant

1997-01-17 Thread Sigbjorn Finne


Chris Dornan writes:
 
 Surely, the argv global-constant proposal is cool.  What is being proposed is
 is a modest extension, namely introducing a constant that is initialised with a
 copy of the command-line arguments.  Cannot this sit along side the existing
 proposal, with each mechanism being used appropriately.  I can think of many
 programs where I would quite usefully use the global constant -- I suspect all
 of them.
 

This is spot on I think, if you want to go the extra mile and provide
an options file, say, then you will have to get out all your plumbing
gear, rather than record options via CAFs, if you so wish. But, the
issue here is *not* how you configure your programs, there's more than
one way to do that (to paraphrase the Perl slogan), but the fact that
argv is *constant* and should be provided as such. I've yet to see a
post contending that argv isn't.

 
 But hold on a moment.
 
 What happens if you have a Stoye-style process model in which you are kicking
 off processes by running `main' programs from a shared repository of program
 modules.  Now each of the processes would be a separate program with its own
 command-line arguments, but the global-constant proposal cannot deal with this
 as many processes with different arguments would be executed from the same
 collection of modules.  Many hackful solutions exist to get around this problem
 to be sure, but the proposal would seem to be decidedly out of place with this
 multi-process execution model.
 

If you're going to provide a functional process abstraction like this,
then you will have to find another way, perhaps
 
  fork :: ([String]{-argv-} - IO ()) - IO ()

(You'd probably also want to do something about I/O and have the
standard handles for each process be separate). Slightly restrictive
you might say, but I personally wouldn't lose any sleep over it
(do you really want a functional OS with one big, shared heap?)

--sigbjorn






Re: Making argv a constant

1997-01-17 Thread Simon L Peyton Jones


Fergus

| I would find Simon's arguments more convincing if he showed
| a convenient idiom that did things properly, rather than a
| convenient way to write broken programs.
| 
| (Doing it properly is probably not too hard, but I'll leave it up to
| the proponents of this proposal to demonstrate this...)

It's hard for me to respond to this since I don't know what you have in mind
when you say "properly".  If you mean proper error reporting, then that's
not difficult:

main = checkArgForErrors argv   
   rest of prog...

I'm not sure what else you had in mind.

Simon






Re: Making argv a constant

1997-01-17 Thread Claus Reinke


"variables won't, constants aren't" (sorry, don't remember the source)

The argv-problem and its proposed solutions:

  1. fetch argv via the IO monad wherever it is needed
 + it works
 - don't want to program everything in monadic style
  2. fetch argv via the IO monad once and pass it around explicitly
 + it works
 - don't want to pass all these parameters around everywhere
 - could just as well use a monad for this - see 1.
  3. make argv a global constant
 + may work (for this problem)
 - needs some ad hoc changes to the language and implementation
  : hmmm, really global, really constant?

Just a thought - wouldn't first class modules help here?
Not that they were available right now, but let me explain the 
idea anyway:

  a) you have a collection of declarations and some of them
  need access to what seem to be constants *for these
  declarations in question*, which is a *local* property.
  b) these `constants' are not really constant - argv contains
  the *parameters* to the executable. The correct alternative
  would be an additional parameter to main, but that's what
  the IO monad is for, isn't it?

So we seem to need a way to *parameterize a collection of declarations*
with a *runtime* value. This is why simple parameterized modules would
not help and, if I see this correctly, why even a separate module
language ala SML extended with higher-order functors would not be
enough here - they explicitly address modules *before* runtime.

But with true first class modules, we could do something like this:

  MyCompiler argv =
struct
  parse = . argv ...,
  typeIt = .. f optimize inline,
  ...
  f opt inl = ... argv ...,  
  ...
  compile = parse  typeIt  ... 
end

  main = getArgv = \argv-
 checkArgvForErrors argv 
 (MyCompiler argv).compile

Not very realistic, not even Haskell (yet), but I hope you get the 
idea.  It will not solve your problem immediately, but it may be the 
generalization you've been looking for. It avoids passing parameters
as global constants and does not bypass the IO monad when doing
the system interactions this thing was designed for. It is modular,
does not break down for the other problem variants mentioned and 
it does not need no ad-hoc restrictions to work.

Of course, if your MyCompiler had only one entry function, a local 
definition instead of the local module would do:

  MyCompiler argv = 
let
  parse =
  type =
  ...
 in parse  type  ..

So first class modules seem to be a natural and useful extension, in
line with usual functional programming techniques. As mentioned in
the other thread, static type inference seems to cost you here: it
converts the simple idea into quite a complex problem. I have also
ignored the issue of (local) type declarations here.

For what its worth,
-- 
Claus ReinkeUniversity of Kiel
email: [EMAIL PROTECTED]Department of Computer Science
http://www.informatik.uni-kiel.de/~cr/  Preusserstr. 1-9,   24105 Kiel






Re: Making argv a constant

1997-01-17 Thread Sigbjorn Finne

Lennart Augustsson writes:
 
 Fergus Henderson wrote:
  Sigbjorn Finne, you wrote:
   
   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!
 

OK, so stdin is not a global constant anymore, but is stashed away in
TLS somewhere. I don't like this at all, for the following reasons:

- one of the touted benefits of using continuations is the ease
  by which you can implement a multi-threaded system, Schemers and ML
  folks have been doing this for years, as you no doubt know better
  than me. Threads in such an implementation have no TLS, that's the beauty
  of them, so your solution would preclude the use of continuations
  here, right? (same goes for Concurrent Haskell, it does not use
  continuations as such, but only record the STG state of a thread in
  a special heap object). 
  
- If you do require multi-threaded Haskell implementations to have
  TLS, your solution would be inefficient, what if you were to
  communicate a value like the following between two threads

 (\x y - hPutStr (if x then stdout else y) "Ay,ay,ay!")

  do you then have to walk over the thunk you're transmitting to
  to hunt for the uses of the thread-local handles, and somehow
  relativise them to the thread you're communicating with? 

But, the standard handles can be made thread-local, just provide
access to them through IO! A straightforward implementation
of IO in a multi-threaded setting might be

 type Triple a = (a,a,a)
 newtype IO a = IO (Triple Handle - _RealWorld - (_RealWorld, a))

Creating new processes (using Concurrent Haskell's forkIO, say) can
then easily be augmented to functionally change the interpretation of
the standard handles for a process. This solution is simple, modular
and does not require TLS or other RTS Magic.

 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!"
 

OK if you *really* want that, it's easy enough to do:

   newtype IntVal = IntVal ((Int - Int) - Int)
  
   lift :: Int - IntVal
   lift v = IntVal (\ f - v f)
  
   run :: IntVal - (Int-Int) - Int
   run (IntVal v) f = v f

   valPlus :: IntVal - IntVal - IntVal
   valPlus (Val v1) (Val v2) = Val (\ f - v1 f + v2 f)

   instance Num IntVal where
 (+) = valPlus
 fromInt n = lift n -- not standard haskell, but you get the idea.
 ...

   main = print (run (2+2) (+1))

   -- prints 6 :-) :-)

I'm only arguing that make the standard handles be connected to IO,
which is the only context they can *ever* be used. Doing so, adds
valuable expressiveness over stdio, which I consider a Good.
But then again, Dennis Ritchie is not my hero :-)

--Sigbjorn






Re: Making argv a constant

1997-01-17 Thread Sigbjorn Finne


Fergus Henderson writes:

 ...
 
 I'm still not entirely happy with the error handling, though.
 As a general rule, I try to use `error' only for internal software
 errors, not for error messages that can result from the user's
 mistakes.  (But perhaps that is another functional programmer's
 death wish... what do other people think about this issue?)
 

On the use of `error', according to my Partain Dictionary, that's not
a death wish, its entry says just Losing :-)

--Sigbjorn






Re: Making argv a constant

1997-01-17 Thread nikhil


Lennart says:

I've sinced changed my mind, maybe it is "a functional programmers
deathwish", but I find the case where you are explicit about what a
function depends on to be more honest and true to the FP spirit.
I've also found it practically useful since you can then change the
values of the given flags locally (which you couldn't do with a global
argv).

Is this an argument against having lexically scoped variables altogether?

(Iknew you were into supercombinators, but this much? :-)

Nikhil






Re: Making argv a constant

1997-01-17 Thread Sigbjorn Finne


Fergus Henderson writes:
 Sigbjorn Finne, you wrote:
  
  OK, so stdin is not a global constant anymore, but is stashed away in
  TLS somewhere.
 
 No! stdin _is_ a global constant.
 What is stashed away in TLS is the binding of stdin to whichever
 file it happens to be bound to.  Of course if your thread implementation
 doesn't have TLS as such, you can put this binding in the thread-local
 IO state.  (Your thread implementation *must* have this, if redirecting
 stdin for a thread can be implemented at all.)
 

Right, the implementation of IO could be an environment + state monad,
carrying around the current bindings for the standard handles (I gave
the type for the obvious way of representing this). But, the *thread
implementation* can be oblivious to all of this, which is a Good Thing  
(threads aren't necessarily IO-bound, you could have one performing
ST actions, for instance).

If I'm understanding Lennart and you correctly (finally, I hear you
say!), the representation you prefer, would have an implementation
something like the following in a multi-threaded setting:

  data Handle
   = Stdin 
   | Stdout
   | Stderr
   | Other _FilePtr -- say

  stdout = Stdout

and then have hPutStr do the following:

  newtype IO a = IO ((Handle,Handle,Handle) - PrimIO a)

  hPutStr :: Handle - String - IO ()
  hPutStr h str (stdin,stdout,stderr) =
   case h of
Stdout   - primPutStr stdout str 
Other fp - primPutStr fp str
_- fail ""


with putStr then just being 

  putStr str = hPutStr stdout str

whereas I want

  stdout = getStdout

  putStr str = 
   do
h - stdout
hPutStr h str  -- primPutStr (+valid handle check), really.

I don't think we're in violent disagreement here - the sink for
standard output is fixed wrt. to the IO context of the thread
executing, but all IO actions have an associated output stream.
My choice of how to do this would require the introduction of
IO operations for accessing a standard handle's current bindings (as
well as setting them), yours wouldn't require an extension - you win :-)

Regards,
--Sigbjorn






Re: Making argv a constant

1997-01-16 Thread Sverker Nilsson

Simon Peyton Jones wrote:
 It was Just Too Painful to pass the flags everywhere.  For example, deep in
 some dark corner of the transformation system there's a constant that
 says how big a function body can be before GHC inlines it.  Threading
 the command-line arguments all the way to that site is desperately painful. 
 It's even worse if you discover that you'd like a command-line-controllable
 thing in a dark corner that doesn't yet have the plumbing... you have to add
 an extra argument to a chain of functions all the way to the top.
 

I'd naively think that you could have put the flags in some structure
that's passed around anyway, like the symbol table? For example
just invent some identifier names that's not legal Haskell and put
the info there.

 Passing the flags around costs extra instructions (not many each time, but a
 lot of times).  Furthermore, even the flag test is expensive.  You can't
 pass 100 flags individually, so you pass a single value and do a lookup each
 time you want to test the flag.  Contrast that with a global thunk that
 gets updated to a boolean the first time you use it.
 

Maybe the symbol table isn't passed around to all dark corners though.

Anyway, what it seems to me you lose by doing it the way you described
is that you are stuck again if some day you want to set those flags
some other way than from the environment variables. For example with
pragmas. You can't compile several modules with different settings
either, without restarting all of the compiler, it seems to me.

Sverker






Re: Making argv a constant

1997-01-16 Thread Simon L Peyton Jones



| Maybe the symbol table isn't passed around to all dark corners though.

Dead right it ain't. There are plenty of places you don't need a symbol
table.

| Anyway, what it seems to me you lose by doing it the way you described
| is that you are stuck again if some day you want to set those flags
| some other way than from the environment variables. For example with
| pragmas. You can't compile several modules with different settings
| either, without restarting all of the compiler, it seems to me.

I regard this as an *advantage*.  If I see

import CmdLineOpts( myFlag )

f x = if myFlag then A
  else B

then I *know* that every call to f will behave like A, or
every call will behave like B.  No chance that some may behave like
one and some like the other.

If I pass the flags as an argument, thus:

f flags x = if (lookup "myFlag" flags) then A 
else B

then I can draw no such conclusion.

The point is, if I *want* to have several behaviours in one run I can
always use this second technique.  But Haskell as it now stands prevents
me from using the first, even when I *don't* want several behaviours in one
run.  I'd be prepared to pay the pain if I wanted the benefit.  Since I
don't want the "benefit" I don't want the pain.  

This message has clarified that there are three (not two) reasons
that argv should be constant

1.  Easier programming
2.  Faster running
3.  Extra reasoning ability (this the new one; every call to
f will behave the same way)

Simon