
Hi Cafe, this is an idea that has been floating in my head for a while, and I’m wondering about its feasibility and, if feasible, complexity (in the range from „trivial“ over “blog post” over “paper” to “thesis”). Application authors in Haskell often face the problem of run-time constants, e.g. values that are expected to be determined once during program start and then stay fixed for the remainder of the run. Good examples are user configuration values (--verbose, certain paths, debugging level, etc.). Usually in Haskell, you’d determine them in the main function and then pass them in an argument to all functions needing them, or you wrap that in a monad. This works and has the advantage of being explicit. One can locally change the value when passing it to another function – this can be a good thing (more powerful) or a bad thing (if the programmer had runtime-constant behavior in mind, an invariant not enforced by the type system or the compiler). The big downside is the verbosity of the approach: A lot of parameters need to be passed, and if one such value is suddenly required in a function where it was not before, this function’s signature and all functions using it have to be modified. Also, I expect that the explicit passing causes a small performance penalty. A less idiomatic approach would be something like this: ====== module M confRef = unsafePerformIO $ newIORef (error "not set yet") conf = unsafePerformIO $ readIORef confRef f = ... conf ... ====== import M main = do ... writeIORef confRef theValue ... f ... ====== This has the nice effect that the programmer can use "conf" as if it is a proper constant value. It could also be quicker, as nothing needs to be passed on the stack. But besides the subtle issues about inlining, this has the big issue of glaring unsafeness: There is no guarantee that confRef is actually set before conf is evaluated, and any code can easily change the confRef anywhere during the runtime. I’d like to propose (on the theoretical level for now, don’t worry) an extension to the language to support _parametrized modules_, which work internally similar to the example above, but with the compiler statically ensuring correctness, where correctness means * The parameter is not evaluated before it is set. * It is set at most once. Rouch syntax sketch: ====== module M parameters (conf1, conf2) f = ... conf ... ====== import M main = do ... M.setParameters someVal1 someVal2 ... f ... ====== where setParameters is a symbol generated by the compiler. The tricky part is, of course, ensuring the correctness. For example while
main = do M.setParameters 1 2 ...f... should be easy to check, how about main = do id $ M.setParameters 1 2 ...f... or even main = do bool <- someIOAction guard bool $ M.setParameters 1 2 ...f... ?
I envision a ghc extensions that would allow to one to hook into the type checker and attach bits of information (here: „uses conf“ and „initizalizes M“) to the types, and also check certain conditions (e.g. a >>= b is invalid if a and b both have „initializes M“ attached). If this extension was loaded when id was compiled, it should probably accept the second case, but when no such information is available, or in the third case, reject the code. A framework for such attached bits would surely enable more extensions that statically check some condition that is hard or unwieldy to express in the type system. I have more ideas in that direction, but before I start brabbling, maybe I should first wait for your reactions. Do you think this could be useful (from a user point of view)? Has this idea maybe already been proposed? Thanks, Joachim -- Joachim "nomeata" Breitner mail@joachim-breitner.de | nomeata@debian.org | GPG: 0x4743206C xmpp: nomeata@joachim-breitner.de | http://www.joachim-breitner.de/