I would also like to strongly discourage code generators. Any code that has to be "generated" can and should have its common characteristics separated out with only unique characterstic remaining typically with an interface (i.e. type class) or polymorphic type dividing the two, creating a separation of concerns (this is really just abstraction).
Every software project which I've worked on that used a code generator turned into a nightmare, because when we find we need to change something about the generator's output, all the already generated code has to be updated manually while at the same time maintaining all of the unique modifications that have been since the code was first generated. It's a horrible duplication of program logic and maintenance work. Of course code generation is perfectly fine when the output is not intended to be read and maintained by a human. For example, a compiler is technically a code generator, but it is purely for optimization purposes and the output is not intended to then be maintained by a human manually. A compiler might unroll a loop repeating the loop body a hundred times causing obvious duplication of logic, but it's fine because the assembler output is not intended to be maintained by a human, only the source input is. Efficiency and maintainability cannot be satisfied at the same time, which is why assembly sucks (not maintainable) and so do dynamic/scripting languages (not efficient), and compiled languages like Haskell are awesome (source code is highly maintainable, compiler output is highly efficient). Anyway, from my experience if you're generating code intended to be maintained by a human, you're doing it wrong. Though I am very interested to hear counter examples. Jesse On 20/08/2010 6:17 PM, Graham Klyne wrote: > Maybe not helpful to you at this stage, but... > > An alternative to generating source code is to factor out the common > "boilerplate" elements into separate functions, suitably > parameterized, and to > use higher order functions to stitch these together. > > An example of this kind of approach, which is handled by code > generation in some > other languages (e.g. lex, yacc, etc), is the Parsec combinator-based > parsing > library (http://www.haskell.org/haskellwiki/Parsec) - instead of > generating > code, the syntax "rules" are written directly using Haskell functions and > assemble the common underlying repeated logic dynamically, behind the > scenes. > > I adopted a development of this approach for a programme with a built-in > scripting language that I implemented some time ago: the scripting > language was > parsed using Parsec, not into a syntax tree, but directly into a > dynamically > assembled function that could be applied to some data to perform the > scripted > function (http://www.ninebynine.org/RDFNotes/Swish/Intro.html). > > What I'm trying to point out here that, rather than go through the > step of > generating source code and feeding it back into a Haskell compiler, it > may be > possible to use higher order functions to directly assemble the > required logic > within a single program. For me, this is one of the great > power-features of > functional programming, which I now tend to use where possible in other > languages that support functions as first class values. > > #g > -- > > Andrew Coppin wrote: >> I'm working on a small Haskell package. One module in particular >> contains so much boilerplate that rather than write the code myself, >> I wrote a small Haskell program that autogenerates it for me. >> >> What's the best way to package this for Cabal? Just stick the >> generated file in there? Or is there some (easy) way to tell Cabal >> how to recreate this file itself? > > > > > _______________________________________________ > Haskell-Cafe mailing list > Haskell-Cafe@haskell.org > http://www.haskell.org/mailman/listinfo/haskell-cafe _______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe