Phil writes:
> I support those who argue AGAINST making argv a constant.
> If it's a problem, let's find a general solution.
>
> One possible solution is a new declaration, of the form:
>
> pseudoconstant <name> <expr>
>
> where <expr> has type (IO t), and <name> is declared with type t.
> (Pick a different keyword if you prefer.) The only tricky issue is
> the order in which the commands of type (IO t) are executed. They
> should clearly precede main, but how should they relate to each other?
> It seems reasonable to restrict this declaration to appear in the same
> module as main, in which case the textual order is sufficient.
>
After having spent little bit of time thinking about the
`performOnceBeforeMain' suggestion, which is the `pseudoconstant' decl
in its raw form, here's some comments on it:
To recap, the original suggestion was to introduce a
function/construct like the following into the language:
performOnceBeforeMain :: IO a -> a
with the behaviour that when executing a program, all the
`performOnceBeforeMain' actions would be performed before starting to
evaluate `main' (making them similar to constructors for static
objects in C++). Using this, argv could then easily made a toplevel
constant:
argv = performOnceBeforeMain (System.getArgs)
main = ...
- It's an interesting idea, but before delving into some of the
more specific problems with it, is it really solving a general
enough problem? The only case I (and others) have come across where
you want to avoid playing the plumbing game for something that's
really constant, is argv. Are there other compelling, general uses
of the construct? I'm not claiming that there aren't, just that I
haven't come across them.
- You want to restrict the use of `performOnceBeforeMain' to
toplevel constants only, and Phil's use of a declaration is
a good way to enforce this.
- When will the init actions be performed? At program startup?
What if your system dynamically loads code? Do you have to
hoist these modules in wholesale at startup, or do you rely on a
sufficiently expressive format for your dyn.libs? (e.g., ELF).
Restricting the use of these decls to the Main module gets
around these worries, but it prevents you from farming out
the handling of argv to a separate options module, say (not quite
true, just harder; you could have the options module and Main be
mutually recursive).
- The construct makes it possible to express the following:
pseudoconstant foo newVar
A global variable...
Sure, you could impose restrictions on the values the init
action is allowed to return (no variables or IO actions embedded
inside them). But, is this language construct useful enough
to warrant all this complexity?
At the danger of sounding like a record player that's stuck,
providing argv as a constant via a library is just what you
want here, because:
- it's constant ;-)
- no language change reqd to accommodate it.
- 98% of all Real Programs use argv for something useful,
(although an app might provide a more user-friendly interface
to configuring some of its options). Hence, it makes good
sense to make access to it easier, if you so wish.
- it makes the everyday lives for the scores of Haskell programmers
a tad more bearable.
--Sigbjorn