Let me see if I understand the rules of this firestorm game: You have
to repeat your ideas some times to push them through the competition?-)
Okay, here we go (simplified proposal follows at the end):
1) the functional solution to the argv-problem would use definitions
local to a local collection of declarations (representing the Main
module or a module imported by Main; in the latter case, parameterized
modules would be required)
2) Haskell's static type inference system puts more restrictions on
local declarations than on global ones; neither first class structures
nor parameterized modules are provided
3) every proposal that does not address the typing problems cannot
solve the full problem (though it might provide a workaround)
4) Mark Jones (is he reading this list?) and others have been working
on the type problem. While they cannot eliminate all restrictions
of a statically typed language based on type inference, it seems
as if they have made some progress. (Not unexpectedly, these
approaches also address the problem of first class structures,
but that's another story)
--------
long term solution:
enhance the type system (the rest should be less difficult)
short term solution:
use a workaround that is compatible with the expected long term
solution and that can be easily removed in favor of such a solution
later
========
In other words, the intermediate solution (or what I see as such;-)
should be just as general as necessary to bridge the gap until the
real solution is available. In particular, users should not be
tempted to use these workarounds in a way that would require major
recoding later. This is based on the feelings expressed by others
(and shared by me) that the workarounds discussed so far are not in
spirit with functional programming.
So, what kinds of workarounds have been proposed so far?
A) make argv a predefined "constant"
main = .. argv ..
B) new construct/function: performOnceBeforeMain :: IO a -> a
argv = performOnceBeforeMain (System.getArgs)
main = .. argv ..
C) new declaration: pseudoconstant <name> <expr>
-- where (name::t) if (expr::IO t)
pseudoconstant argv System.getArgs
main = .. argv ..
I support the search for general solutions. However, since a general
and functional solution to this problem seems to be possible, I have
to argue against generalizing ad-hoc solutions in ways that run
counter to my preferred view of functional languages.
The whole development seems to drift towards sequences of
declarations that have to be evaluated in textual order for their
implicit side effects - similar to the way this is done in Standard
ML. SML is a fine language, and in allowing side effects, it makes a
mostly functional style attractive to a lot of people. Nevertheless,
SML users pay for this "freedom", and I like the idea of keeping
Haskell as a pure alternative for those who want more.
Also, such "reasonable default"-solutions (in the order of
declaration, once before main, ..) tend to be specific to what seems
reasonable now, and thus get in the way fast when our view of things
improves later (e.g., non-UNIX-environments have been mentioned already).
This can only get worse if `the only tricky issue is the order in
which the commands of type (IO t) are executed'. Isn't this the main
problem behind the integration of imperative and functional
programming?
###### BREAKPOINT (for those who skipped the previous paragraphs;-)
In view of this, the smallest evil seems to be a variant of A,
providing one record of once-per-runtime read-only parameters
(including argv, env,..?) to the executable. Using only one (record)
parameter facilitates later modifications/extensions.
Why not make it a parameter to Main? This way, the dependencies for
this pseudoconstant would be clear (remember that they are no longer
recorded in the IO monad or as parameters to main). Furthermore,
allowing parameters for modules in general (even without going all
the way to first class modules) would provide the means to propagate
the once-per-runtime parameters to other modules imported by Main.
module Main env where
import Compiler (env.argv) (env.env "MY_LIBRARY_PATH")
main = .. (env.env "HOME") ..
Without a major overhaul of the module system, the use of
parameterized modules may be restricted, but if a simple variant is
good enough for the current problem, it will at least be compatible
with future extensions.
Just in case some of you still insist on having the pseudoconstants
depend on commands: there should be a way to restrict the commands in
performOnceBeforeMain to state readers (in which case the order of
execution would not matter), for otherwise main could hardly be
called main anymore, could it?
pseudoconstant rest_in_peace (System.system "rm -rf /")
-- test whether we were on a UNIX system.
-- system dependent, should probably be moved
-- into some well hidden System module
main = return ()
-- () for `nothing'
-- don't forget to switch on the optimizer!
Best regards,
--
Claus Reinke University of Kiel
email: [EMAIL PROTECTED] Department of Computer Science
http://www.informatik.uni-kiel.de/~cr/ Preusserstr. 1-9, 24105 Kiel