Re: [Haskell-cafe] Solving the configuration problem with parametrized modules
Joachim point taken, if you are already building on a transformer Joachim stack, adding yet another layer is not a problem. I’m having Joachim mainly pure code in mind. I think we need an other word than pure here. Usually, we understand pure as always producing the same result when given the same parameters. Here, always really means always, and does not depend on the run-time context of the program. So obviously, a really pure function can't use side-effect run-time constants. IIUC, what you want is run-time qualified functions, or functions that In the scope of a run, always produce the same result when given the same parameters. Is that right ? -- Paul ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] Solving the configuration problem with parametrized modules
Hi, Am Donnerstag, den 08.09.2011, 09:21 +0200 schrieb Paul R: Joachim point taken, if you are already building on a transformer Joachim stack, adding yet another layer is not a problem. I’m having Joachim mainly pure code in mind. I think we need an other word than pure here. Usually, we understand pure as always producing the same result when given the same parameters. Here, always really means always, and does not depend on the run-time context of the program. So obviously, a really pure function can't use side-effect run-time constants. IIUC, what you want is run-time qualified functions, or functions that In the scope of a run, always produce the same result when given the same parameters. Is that right ? yes, although I understand “pure” as that, e.g. always within one run of the program. This is in line with some other “constants” as those in in GHC.Constants and System.Info in base. What breaks if we allow functions to be pure only within one run of the program? Greetings, Joachim -- Joachim nomeata Breitner m...@joachim-breitner.de | nome...@debian.org | GPG: 0x4743206C xmpp: nome...@joachim-breitner.de | http://www.joachim-breitner.de/ signature.asc Description: This is a digitally signed message part ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] Solving the configuration problem with parametrized modules
Hi, Am Dienstag, den 06.09.2011, 08:15 +1000 schrieb Erik de Castro Lopo: Joachim Breitner wrote: 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. Can't this be mostly solved by putting all these configuration parameters in a struct and then using implicit parameters: http://www.haskell.org/ghc/docs/latest/html/users_guide/other-type-extensions.html#implicit-parameters The nice thig about this approach is that is not a single unsafe operation needed. that would work sufficiently if we had support partial type signatures, e.g. could specify the types of functions “up to” implicit parameters. Then, using a parameter somewhere where it was not used before does not require propagating code changes. Also, implicit parameters have the feature that they can be changed locally. Note that using unsafe operations is not a problem if the compiler can verify that they are not unsafe after all, which is what I am hoping for. Let me motivate my approach by an analogue. All our existing Haskell programs would be fine without the type systems, just writing new ones would be more difficult. This is because the type systems (basically) only limits the set of valid programs, while enforcing some correctness condition (here: type safety). This is analogous to using a regular expression to define some language of valid words, e.g. well-formed e-mail-addresses. Now assume we want to add an additional check, e.g. that the address contains one of a list of keywords, anywhere. We could create a second regular expression of the form .*(word1|word2|...).* and make sure both regular expressions match. Alternatively, using our CS education, we know we could construct a single regular expression that accepts the intersection of the two languages. But we would not do that, because the expression would become horribly convoluted. Back to my proposal, I see a similar pattern here. We have a good type system to enforce type safety. Now I come along and want to enforce a different, additional constraint (correct use of run-time constants). I could try hard to enforce it in the type systems, making it more complicated and maybe interfering with other uses of it. Or I could add a second checker that, orthogonal to and maybe using results of the type checker, enforces this condition. I’d even go a step further and say that having an accessible, extensible interface in ghc to add additional checks, that also allows to export “type” signatures in the module interfaces, would open a door to many more possible improvements. For example, the recently added notion of Safe modules falls into this category. Now imagine that you’d not have to hack on ghc itself but just build a Haskell library and specify some flag during compilation to add a new property verifying layer to the language, like bounding rounding errors in floating point calculations, or even an interface to a full theorem proof checker... but I digress. :-) Greetings, Joachim -- Joachim nomeata Breitner m...@joachim-breitner.de | nome...@debian.org | GPG: 0x4743206C xmpp: nome...@joachim-breitner.de | http://www.joachim-breitner.de/ signature.asc Description: This is a digitally signed message part ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] Solving the configuration problem with parametrized modules
Joachim Breitner wrote: ...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... 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. I'm struggling to understand what problem you are trying to solve. We're talking about passing a single parameter - a record type, or a shallow tree, or something else extremely simple. In the monadic case, we're adding a single Reader component to the transformer stack. I'm currently working on a large system, consisting of hundreds of modules and tens of thousands of lines of code. There are hundreds of configuration parameters, coming from configuration files, modules of compiled-in constants, and the UI. Different subsets of the parameters are needed in various subsystems. Doing that in Haskell has been an absolute pleasure, much much simpler than in any other language I've used for a system of this size. (I'll spare you the horror of what I had to do once for a large system written in C++...) I barely have to think about it - the types reflect the relationships between the configuration and the various parts of the system, and Haskell's type system does the rest automatically, guaranteeing correctness. What else could you ask for? Also, I expect that the explicit passing causes a small performance penalty. We're been processing gigabytes of data - doing non-trivial operations including a kind of image recognition and more - so far with nearly imperceptible delay. The bottleneck, if there is one, will certainly not be the configuration subsystem. I know some Haskell libraries use constructor hiding, or even the data-default package which uses generics, to add more flexibility to the configuration system. But I don't feel the need even for those. I certainly wouldn't dream of dragging in type-level olegery, unsafe coercion, implicit parameters and other experimental extensions. Simplicity just works. What case are you thinking about? A system several orders of magnitude more complex? Some special case that creates difficulty? Thanks, Yitz ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] Solving the configuration problem with parametrized modules
Joachim Breitner m...@joachim-breitner.de writes: 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.). There are two aspects to this, both of which have potential solutions that I’ve been thinking about on and off for a long time. The first is command line arguments. As far as I’m concerned they ought to be passed as a parameter to the whole programme. So instead of main being a value exported to the outside world and all importing of values being done through the IO monad, we would have main going out and argv::[String] as a global variable (which, of course would not change during any run of the programme). The alternative version of this, to make main::[String] - IO ExitCode has a superficial cleanliness but doesn’t help with the general problem of having to pass these things about, and in fact makes no real difference to the referential transparancy of a programme. The second is configuration data in files. This seems to fall into two parts: the data that can be fixed at link time and the data that changes from run to run. For the former, a simple solution would be to have a facility to compile a module from non-haskell data. This can be done with template Haskell doing IO. So that leaves configuration data that changes from run to run. -- Jón Fairbairn jon.fairba...@cl.cam.ac.uk http://www.chaos.org.uk/~jf/Stuff-I-dont-want.html (updated 2010-09-14) ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] Solving the configuration problem with parametrized modules
Hi Jon, Am Dienstag, den 06.09.2011, 14:01 +0100 schrieb Jon Fairbairn: Joachim Breitner m...@joachim-breitner.de writes: 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.). There are two aspects to this, both of which have potential solutions that I’ve been thinking about on and off for a long time. The first is command line arguments. As far as I’m concerned they ought to be passed as a parameter to the whole programme. So instead of main being a value exported to the outside world and all importing of values being done through the IO monad, we would have main going out and argv::[String] as a global variable (which, of course would not change during any run of the programme). Right. You already think of the command line parameters as constants and expect them to be provided to you as such. My idea enables that, but not only for command line parameters but anything that you know is initialized at the start of the program. Greetings, Joachim -- Joachim Breitner e-Mail: m...@joachim-breitner.de Homepage: http://www.joachim-breitner.de Jabber-ID: nome...@joachim-breitner.de signature.asc Description: This is a digitally signed message part ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] Solving the configuration problem with parametrized modules
Hello, Am Dienstag, den 06.09.2011, 15:17 +0300 schrieb Yitzchak Gale: We're talking about passing a single parameter - a record type, or a shallow tree, or something else extremely simple. In the monadic case, we're adding a single Reader component to the transformer stack. point taken, if you are already building on a transformer stack, adding yet another layer is not a problem. I’m having mainly pure code in mind. Also, I expect that the explicit passing causes a small performance penalty. We're been processing gigabytes of data - doing non-trivial operations including a kind of image recognition and more - so far with nearly imperceptible delay. The bottleneck, if there is one, will certainly not be the configuration subsystem. Hmm, maybe I am underestimating ghc, but I’d expect that while it could create very good code for some tight recursion loop in the IO monad, I’m not so confident that it could do that for a recursion in (ReaderT IO) or an even more complex monad stack. But you are right, other than this special case, the performance issues are surely not in setting parameters. What case are you thinking about? A system several orders of magnitude more complex? Some special case that creates difficulty? I think the benefit you get from being able to treat runtime constants as plain values manifests mostly when writing pure code. If your code has already been written or re-written in monadic style, adding a transformation layer is indeed less of a problem. Greetings, Joachim -- Joachim Breitner e-Mail: m...@joachim-breitner.de Homepage: http://www.joachim-breitner.de Jabber-ID: nome...@joachim-breitner.de signature.asc Description: This is a digitally signed message part ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] Solving the configuration problem with parametrized modules
On 6 September 2011 15:33, Joachim Breitner m...@joachim-breitner.de wrote: I think the benefit you get from being able to treat runtime constants as plain values manifests mostly when writing pure code. If your code has already been written or re-written in monadic style, adding a transformation layer is indeed less of a problem. Run time constants are still an effect, though, just like error, state, IO... that's why they are usually propagated with the Reader monad or sometimes implicit params. This does seem to irritate newcomers on Stack Overflow who don't equate constant (but not statically known) values with more active effects like state or file IO. ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
[Haskell-cafe] Solving the configuration problem with parametrized modules
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 m...@joachim-breitner.de | nome...@debian.org | GPG: 0x4743206C xmpp: nome...@joachim-breitner.de | http://www.joachim-breitner.de/ signature.asc Description: This is a digitally signed message part ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] Solving the configuration problem with parametrized modules
On Mon, Sep 5, 2011 at 1:43 PM, Joachim Breitner m...@joachim-breitner.de wrote: Do you think this could be useful (from a user point of view)? Has this idea maybe already been proposed? How does it compare with Oleg's typeclass approach? http://okmij.org/ftp/Haskell/types.html#Prepose -- gwern http://www.gwern.net ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] Solving the configuration problem with parametrized modules
Hi, Am Montag, den 05.09.2011, 14:35 -0400 schrieb Gwern Branwen: On Mon, Sep 5, 2011 at 1:43 PM, Joachim Breitner m...@joachim-breitner.de wrote: Do you think this could be useful (from a user point of view)? Has this idea maybe already been proposed? How does it compare with Oleg's typeclass approach? http://okmij.org/ftp/Haskell/types.html#Prepose the big difference is that Oleg’s approach exploits the existing type system. This is elegant, as it does not need additional support by the compiler. The “disadvantage” is that you have to still have to adjust type signatures (quotes because there is some value in explicitly stating the use of parameters), and it might (possibly) interfere with other fancy usages of of the type system. My proposal adds a second layer of “type” checking, i.e. the terms have their types as before (and all guarantees by the type system prevail), and a second round of inference and checking ensures the additional property of properly setting and using the module¹ parameters. Another difference is that his system allows for local changes of parameters, while mine deliberately ensures that a parameter really has exactly one value during one execution of the program. Finally, I’d say that my approach is easier to grasp and use by the programmer. Greetings, Joachim ¹ I guess the same approach works even when parameters are not tied to a specific module, but live on their own. But I guess for clarity of syntax and use it makes sense to tie them to modules, at least at first. -- Joachim nomeata Breitner m...@joachim-breitner.de | nome...@debian.org | GPG: 0x4743206C xmpp: nome...@joachim-breitner.de | http://www.joachim-breitner.de/ signature.asc Description: This is a digitally signed message part ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] Solving the configuration problem with parametrized modules
Joachim Breitner wrote: 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. Can't this be mostly solved by putting all these configuration parameters in a struct and then using implicit parameters: http://www.haskell.org/ghc/docs/latest/html/users_guide/other-type-extensions.html#implicit-parameters The nice thig about this approach is that is not a single unsafe operation needed. Erik -- -- Erik de Castro Lopo http://www.mega-nerd.com/ ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
Re: [Haskell-cafe] Solving the configuration problem with parametrized modules
On Mon, Sep 5, 2011 at 3:15 PM, Erik de Castro Lopo mle...@mega-nerd.comwrote: Can't this be mostly solved by putting all these configuration parameters in a struct and then using implicit parameters: Implicit parameters seem like a fair option. And propagating: (?fooConf :: FooConf) = ... isn't any more difficult than explicit parameters in the type. I guess the question is whether it is the parameterization or the *staging *that seems more relevant. ___ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe