Daan Leijen wrote:
[snip]
> Representing the 'args' as a value in haskell is probably not
> the right thing to do. For one thing, it is not possible to substitute the
> value 'args' with its definition, since it is unknown until load time.
>
> I think that the 'dynamic environment' info is much better represented with
> implicit arguments. (already implemented by Jeffrey Lewis in the november
> hugs release).
> (Implicit Parameters: Dynamic Scoping with Static Types. Jeffrey Lewis, Mark
> Shields,
> Erik Meijer, John Launchbury:
> http://www.cse.ogi.edu/~mbs/pub/implicit.ps.gz )
>
> The type of main would than be:
>
> > main :: (?arguments, ?environment) => IO ()
>
> And we could use these arguments anywhere in the haskell program
> (without making everything part of the IO monad)
[snip]
I like the implicit parameter idea a lot. All the uses of unsafePerformIO
within the main core of the UniForM workbench are there to do initialisation.
Suppose for example you have a single graphics context (I don't
care what sort of graphics context, maybe a text window or an X server)
for the program. You are provided with something like:
getContext :: IO Context -- to be used at the start of the program
writeStringToContext :: String -> Context -> IO ()
To avoid passing the context all over, I think the current best solution is
something like:
programContext = unsafePerformIO (getContext)
writeString s = writeStringToContext s programContext
The UniForM code does this sort of thing several times. I don't actually object
to using functions with "unsafe" in their name, but there are two serious problems
with this approach:
(1) There is a serious gotcha because you don't actually know when the context
will be opened. Probably the window or whatever will only be created the
first time you try to do something with it, which may be at any time or never.
(2) The whole idea of compositional IO is destroyed. For example, given a main
action, you cannot clone it to get two independent universes; you are stuck
with just one monolithic universe.
If we had implicit parameters then all graphics functions would have types
(? context :: Context) => (explicit arguments) => IO (result) and the main
function would be something like
do
context <- getContext
doBusiness with context=context