
Hello everyone, After a month or so spent on stabilizing DData, I think I've reached a point where it is hopefully acceptable for everyone. In any case, I don't feel like I can make it much better (within the self-imposed restrictions). Therefore, I hereby submit it to the people in charge of the hierarchical libraries, for integration. Of course, if any specific detail deserves work, I remain available. The code/doc is at the usual url: http://users.skynet.be/jyp/DData/doc/ http://users.skynet.be/jyp/DData/ddata.tar.gz Thank you all for your feedback, Cheers, JP. __________________________________ Do you Yahoo!? Yahoo! Small Business $15K Web Design Giveaway http://promotions.yahoo.com/design_giveaway/

JP Bernardy wrote:
[...] Therefore, I hereby submit it to the people in charge of the hierarchical libraries, for integration. Of course, if any specific detail deserves work, I remain available. [...]
I could add DData to the hierarchical libraries in the fptools repository, but first a few points should be clarified: * Who will be the maintainer? Daan? JP? Whoever it is, he will need write access to the repository. * What about the license? I can't find something about this on Daan's page. I propose to use the standard BSD license with Daan and JP as the copyright holder, but I think the final decision on this should be made by Daan. * I'm not sure about the module names, but simply DData as the root is not very nice. What about Data.DData? Something more descriptive would be even nicer, because the module names should describe the functionality, not the genesis of the modules. Using "DData" as the package name is fine. Suggestions welcome... * Using DData as a documentation container module is a creative solution, :-) but a little bit uncommon IMHO. What about renaming it to a sibling module like DData.Documentation or DData.Conventions? Cheers, S.

Am Montag, 5. April 2004 13:56 schrieb Sven Panne:
[...]
I'm not sure about the module names, but simply DData as the root is not very nice. What about Data.DData? Something more descriptive would be even nicer, because the module names should describe the functionality, not the genesis of the modules. Using "DData" as the package name is fine. Suggestions welcome...
If I remember correctly, DData was intended to be the next-generation standard set of collection modules. So, maybe, we should just name the modules Data.Map, Data.Seq, etc. I think, it was already said that this should probably be done. A problem is Data.Set but there may be a solution for this. Since DData will not be one collection library beside others but *the* collection library, we should avoid the name "DData" as part of a module name.
[...]
Wolfgang

Wolfgang Jeltsch wrote:
If I remember correctly, DData was intended to be the next-generation standard set of collection modules. So, maybe, we should just name the modules Data.Map, Data.Seq, etc. I think, it was already said that this should probably be done.
If that's the case, it's fine with me. It should then be in the base package, not in a separate one.
A problem is Data.Set but there may be a solution for this. [...]
I've just made a quick test, and it seems that there exists a simple solution for this: For a transitional time, Data.Set exports both the old API (and marks it as DEPRECATED) and the new API, which is easy because there is no incompatible overlap. Cheers, S.

hello, irrespective of if DData is "the" data structure library (whatever that means), or simply another library, could we avoid adding it to the base package? it would be much nicer, if the base package was split into more components. and it would also be nice if i can go and download DData on its own, whenever there are bugfixes, or improvements, without needing to download GHC with it. i don't see any reason why DData should be part of "base". as for the hirarchical name, DData.Set etc seems perfectly fine for me (and please no Data.DData.Set, or Data.Structures.Conrete.DData.Set :-) ), especially since DData aims to provide concrete implementations. so when i import DData.Set i know i am getting the set implementation from DData --- seems nice and simple. bye iavor Sven Panne wrote:
Wolfgang Jeltsch wrote:
If I remember correctly, DData was intended to be the next-generation standard set of collection modules. So, maybe, we should just name the modules Data.Map, Data.Seq, etc. I think, it was already said that this should probably be done.
If that's the case, it's fine with me. It should then be in the base package, not in a separate one.
A problem is Data.Set but there may be a solution for this. [...]
I've just made a quick test, and it seems that there exists a simple solution for this: For a transitional time, Data.Set exports both the old API (and marks it as DEPRECATED) and the new API, which is easy because there is no incompatible overlap.
Cheers, S.
_______________________________________________ Libraries mailing list Libraries@haskell.org http://www.haskell.org/mailman/listinfo/libraries

I wrote:
Wolfgang Jeltsch wrote:
A problem is Data.Set but there may be a solution for this. [...]
I've just made a quick test, and it seems that there exists a simple solution for this: For a transitional time, Data.Set exports both the old API (and marks it as DEPRECATED) and the new API, which is easy because there is no incompatible overlap.
BTW, there is Data.Queue, too, but the same solution would work there. Cheers, S.

On Mon, Apr 05, 2004 at 03:53:48PM +0200, Wolfgang Jeltsch wrote:
If I remember correctly, DData was intended to be the next-generation standard set of collection modules. So, maybe, we should just name the modules Data.Map, Data.Seq, etc. I think, it was already said that this should probably be done. A problem is Data.Set but there may be a solution for this.
I think this may be controversial. In particular, there's already Data.Edison, which is competing, and some people feel strongly that a class-based approach to overloading should be at least supported. I think this might be a good case for having a 'selector' library. Put DData under Data.DData.*, and have Data.Set (e.g.) re-export Data.DData.Set (since that's the most complete implementation at the moment). Peace, Dylan

G'day all.
Quoting Dylan Thurston
I think this may be controversial. In particular, there's already Data.Edison, which is competing, and some people feel strongly that a class-based approach to overloading should be at least supported.
Speaking as the guy currently responsible for hacking on Edison (despite not being particularly responsible in this duty), I have no problem with rebuilding it as a layer on top of DData. Indeed, integrating the two a bit more closely might settle some arguments, at least for a while. Cheers, Andrew Bromage

On Mon, 5 Apr 2004, Dylan Thurston wrote:
I think this might be a good case for having a 'selector' library. Put DData under Data.DData.*, and have Data.Set (e.g.) re-export Data.DData.Set (since that's the most complete implementation at the moment).
Don't want to argue, but I think, Dessy is "more complete" (although perhaps not as efficient, etc.). Just that so many people are now working on, working with and discussing about DData doesn't make it inevitably better ;-> Robert

Hi,
I could add DData to the hierarchical libraries in the fptools repository, but first a few points should be clarified:
Indeed, I just wanted to make plain that I was done with it.
* Who will be the maintainer? Daan? JP? Whoever it is, he will need write access to the repository.
I'm ready to do it, though if Daan wishes, that's fine don't want to take it over from Daan.
* What about the license? I can't find something about this on Daan's page. I propose to use the standard BSD license with Daan and JP as the copyright holder, but I think the final decision on this should be made by Daan.
I think Daan has already committed to a license, BSD style.
* Using DData as a documentation container module is a creative solution, :-)
Thanks :)
but a little bit uncommon IMHO. What about renaming it to a sibling module like DData.Documentation or DData.Conventions?
I think haddock has an option to add prefix documentation to a set of modules, though I don't know if it is applicable given the build process. Cheers, JP. __________________________________ Do you Yahoo!? Yahoo! Small Business $15K Web Design Giveaway http://promotions.yahoo.com/design_giveaway/

On Mon, 5 Apr 2004 04:19:15 -0700 (PDT), JP Bernardy
After a month or so spent on stabilizing DData, I think I've reached a point where it is hopefully acceptable for everyone. In any case, I don't feel like I can make it much better (within the self-imposed restrictions).
Therefore, I hereby submit it to the people in charge of the hierarchical libraries, for integration. Of course, if any specific detail deserves work, I remain available.
Hi JP, Can we delay it for a few weeks more? I haven't had much time yet to look into it in detail. Furthermore, we should add the BSD license to it all. All the best, -- Daan.
The code/doc is at the usual url: http://users.skynet.be/jyp/DData/doc/ http://users.skynet.be/jyp/DData/ddata.tar.gz
Thank you all for your feedback,
Cheers, JP.
__________________________________ Do you Yahoo!? Yahoo! Small Business $15K Web Design Giveaway http://promotions.yahoo.com/design_giveaway/ _______________________________________________ Libraries mailing list Libraries@haskell.org http://www.haskell.org/mailman/listinfo/libraries

Just a small remark: The DData modules are all marked as "portable", which is not entirely correct, because they import Data.Monoid, which is not portable. A possible solution/workaround for this would be wrapping these Monoid instances into #ifdefs, depending on the Haskell system in question. If I see this correctly, this would only be an issue for Hugs in Haskell98 mode, but the API can't depend on command line flags. Hmmm, not very nice. Better suggestions appreciated... Cheers, S.

On Mon, Apr 05, 2004 at 04:51:15PM +0200, Sven Panne wrote:
Just a small remark: The DData modules are all marked as "portable", which is not entirely correct, because they import Data.Monoid, which is not portable. A possible solution/workaround for this would be wrapping these Monoid instances into #ifdefs, depending on the Haskell system in question.
How about making Data.Monoid portable, by replacing the a -> a instance with one for a newtype?

ross@soi.city.ac.uk wrote:
How about making Data.Monoid portable, by replacing the a -> a instance with one for a newtype?
Although this would change the interface of Data.Monoid a tiny bit, this seems the most attractive solution. I seriously doubt that the a -> a instance is really widely used... Do you have a concrete newtype in mind? I'm currently not sure if we already have something like this... Cheers, S.

On Mon, Apr 05, 2004 at 06:13:29PM +0200, Sven Panne wrote:
ross@soi.city.ac.uk wrote:
How about making Data.Monoid portable, by replacing the a -> a instance with one for a newtype?
Although this would change the interface of Data.Monoid a tiny bit, this seems the most attractive solution. I seriously doubt that the a -> a instance is really widely used...
Hmm, ShowS is a special case.
Do you have a concrete newtype in mind? I'm currently not sure if we already have something like this...
newtype Endo a = Endo { runEndo :: a -> a }

Am Montag, 5. April 2004 18:20 schrieb ross@soi.city.ac.uk:
[...]
newtype Endo a = Endo { runEndo :: a -> a }
Is "endo" a usual mathematical term? If not, it probably would make many mathematicians think that it means "endomorphism" but Endo is not necessarily an endomorphism. Wolfgang

Please, no #ifdef's in standard library code! Dealing with these on Windows systems (for which there is no out-of-the-box CPP) has been one of my messiest problems with existing (non-standard) library, figuring out how to set up the necessary environment to create the symbol definitions required and then to ensure the code is properly processed, etc. Worse, when the standard library code contains #ifdefs, it makes it even more difficult to write applications using such libraries that are easily distributed and used by non-Haskell programmers. Asking a user to install a Haskell run-time is one thing, but requiring them to figure out how to get all the libraries to compile can be a major barrier to adoption. ... So that's my plea. What to do about it? Some thoughts: (a) where possible, use "run-time" tests rather than "compile-time" code selection. If the conditions are constant True or False, surely a compiler should be able to eliminate the redundant code? (b) one place where the above cannot work is where different module imports are required on different systems. I don't have a ready answer, but maybe one is to work to eliminate spurious differences between systems (I think the library infrastructure project may help here). (c) another problem area is where type definitions (incl. function interfaces) differ between systems. Again, eliminating spurious differences would help. (d) For those differences that cannot be eliminated implementing (in Haskell) a portable preprocessor that can ship as part of every Haskell environment? (e) Where #ifdefs really are needed, work to confine them to a very small number of modules, rather than scattering them throughout some code. In this way, where necessary, a manual edit of the file becomes a feasible proposition. For example, this could be done for differing imports, and in many cases could be done for differing type declarations. In the long run, I thing the goal should be to aim for a standard run-time platform that is common across all "standard" Haskell systems, which is simply used by add-on library code. With a very few exceptional functions, languages such as Python and Java achieve this very well. #g -- At 16:51 05/04/04 +0200, you wrote:
Just a small remark: The DData modules are all marked as "portable", which is not entirely correct, because they import Data.Monoid, which is not portable. A possible solution/workaround for this would be wrapping these Monoid instances into #ifdefs, depending on the Haskell system in question. If I see this correctly, this would only be an issue for Hugs in Haskell98 mode, but the API can't depend on command line flags. Hmmm, not very nice. Better suggestions appreciated...
Cheers, S.
_______________________________________________ Libraries mailing list Libraries@haskell.org http://www.haskell.org/mailman/listinfo/libraries
------------ Graham Klyne For email: http://www.ninebynine.org/#Contact

Am Dienstag, 6. April 2004 11:39 schrieb Graham Klyne:
Please, no #ifdef's in standard library code!
You need them if you want you use deriving clauses and Haddock at the same time, since Haddock doesn't fully understand deriving.
[...]
Wolfgang

At 16:56 06/04/04 +0200, Wolfgang Jeltsch wrote:
Am Dienstag, 6. April 2004 11:39 schrieb Graham Klyne:
Please, no #ifdef's in standard library code!
You need them if you want you use deriving clauses and Haddock at the same time, since Haddock doesn't fully understand deriving.
This particular example gives me a certain tail-wags-dog feeling... #g ------------ Graham Klyne For email: http://www.ninebynine.org/#Contact

Am Dienstag, 6. April 2004 11:39 schrieb Graham Klyne:
Please, no #ifdef's in standard library code!
At 16:56 06/04/04 +0200, Wolfgang Jeltsch wrote:
You need them if you want you use deriving clauses and Haddock at the same time, since Haddock doesn't fully understand deriving.
On Tue, 6 Apr 2004, Graham Klyne wrote:
This particular example gives me a certain tail-wags-dog feeling...
Yes, apart from the use in Macros and such, preprocessing is really a workaround for problems that should not be there. That's why every new programming language comes without a preprocessor, but after some time when incompatibilities arise, a preprocessor appears. That's because programmers tend to do a "local fix" instead of eliminate the root problem, that is, incompatibilities between systems. The problem is, that the preprocessor does make things more complicated, not only for the programmer/user, but also for other applications that work with the code: how should they be treated by a documentation generator, by a refactoring tool, by testing tools, and so on? I think what Haskellers (and others) can do in most cases is to factor out platform dependent parts to mini-modules which have different implementations but the same interface. The version of such a module is choosen by the path it resides in during the build process. (Simplest case: the -i option of the compiler.) This also has the advantage, that the dependencies are made explicit, while preprocessing is a very implicit technique, e.g. you have to check type and even syntactic correctness of each possible version separately. For example (for JP!) the #ifdefs in DData could nicely be factored away with this, and we could even have all the bitfiddling code in one module, eliminating redundancy between Maps and Sets... So please no preprocessing in any code! Robert

Robert Will wrote:
Yes, apart from the use in Macros and such, preprocessing is really a workaround for problems that should not be there. That's why every new programming language comes without a preprocessor, but after some time when incompatibilities arise, a preprocessor appears. That's because programmers tend to do a "local fix" instead of eliminate the root problem, that is, incompatibilities between systems.
Well, I hate to repeat myself, but this oversimplifies things a bit and ignores the fact that macros are quite useful as a syntactic abstraction, see one of my previous posts. One of the main goals in writing good SW is avoiding redundancy, and if the language in question doesn't allow us to abstract what we want to do several times, let's use macros! It's infinitely better than using cut-n-paste with slight variations. The real question should be what preprocessor to use. Admittedly, CPP is not ideal for Haskell, because it's totally unaware of the language it is processing, has no mechanisms for hygienic macros (see, e.g. Scheme), etc. Template Haskell might be a better choice, but only if one doesn't care about portability between different Haskell systems.
[...] I think what Haskellers (and others) can do in most cases is to factor out platform dependent parts to mini-modules which have different implementations but the same interface.
Again, this is a valid argument for toy programs/libraries, but there are cases where this is particularly bad: I definitely won't duplicate hundreds of "foreign imports", just because WinDoze DLLs have a different calling convention C. This would be a maintenance nightmare.
[...] So please no preprocessing in any code!
A more realistic plea would be: As little preprocessing as possible in a few selected places! Cheers, S.

Am Donnerstag, 15. April 2004 11:35 schrieb Robert Will:
[...]
I think what Haskellers (and others) can do in most cases is to factor out platform dependent parts to mini-modules which have different implementations but the same interface. The version of such a module is choosen by the path it resides in during the build process. (Simplest case: the -i option of the compiler.) This also has the advantage, that the dependencies are made explicit, while preprocessing is a very implicit technique, e.g. you have to check type and even syntactic correctness of each possible version separately.
I think, this isn't a solution for the problem I originally spoke about, namely the inability of Haddock to handle deriving clauses fully. Of course, the best solution here would be if Haddock would fully support deriving but I don't want to put pressure onto Simon Marlow ;-).
[...]
Wolfgang

Graham Klyne
Please, no #ifdef's in standard library code!
Much as we all hate cpp, I'm afraid the standard libraries are already heavily littered with #ifdefs. Getting rid of them is basically impossible.
(a) where possible, use "run-time" tests rather than "compile-time" code selection. If the conditions are constant True or False, surely a compiler should be able to eliminate the redundant code?
Almost never applicable. #ifdefs are generally used to cater for system differences, so more than likely the False branch simply won't compile.
(c) another problem area is where type definitions (incl. function interfaces) differ between systems. Again, eliminating spurious differences would help.
There should be no externally visible type differences in standard libraries. But internal to the library, different systems might indeed use different representations. For an optimising compiler like GHC this is really important, since certain extensions are a big help, but simpler systems like Hugs and nhc98 still need a viable Haskell'98 representation if possible.
(d) For those differences that cannot be eliminated implementing (in Haskell) a portable preprocessor that can ship as part of every Haskell environment?
I think this is ultimately going to be the most viable solution. Let's write a simple 'hspp' (in Haskell?) that is backward compatible with 'cpp -traditional' (although we might also design a newer nicer syntax too), and distribute it with every compiler. It can't be too difficult, surely? Half of the cpp parsing/selection code is already available within hmake. I would take on the project myself, if I had time. Regards, Malcolm

At 16:12 06/04/04 +0100, Malcolm Wallace wrote:
Graham Klyne
writes: Please, no #ifdef's in standard library code!
Much as we all hate cpp, I'm afraid the standard libraries are already heavily littered with #ifdefs. Getting rid of them is basically impossible.
I guess it's the community's choice of what is important, but in my experience this is a major impediment to distributing portable programs written in Haskell for use by non-Haskellite end users.
(c) another problem area is where type definitions (incl. function interfaces) differ between systems. Again, eliminating spurious differences would help.
There should be no externally visible type differences in standard libraries. But internal to the library, different systems might indeed use different representations. For an optimising compiler like GHC this is really important, since certain extensions are a big help, but simpler systems like Hugs and nhc98 still need a viable Haskell'98 representation if possible.
So I would hope, but I seem to recall coming across some variations of function parameters between systems. I don't remember where. I'm less concerned by the internal workings of a particular Haskell platform, just what's presented to an application program.
(d) For those differences that cannot be eliminated implementing (in Haskell) a portable preprocessor that can ship as part of every Haskell environment?
I think this is ultimately going to be the most viable solution.
Sigh! It seems perverse that a high-level programming system like Haskell remains dependent on age-old assembler-programming techniques. But if so be it...
Let's write a simple 'hspp' (in Haskell?) that is backward compatible with 'cpp -traditional' (although we might also design a newer nicer syntax too), and distribute it with every compiler. It can't be too difficult, surely? Half of the cpp parsing/selection code is already available within hmake. I would take on the project myself, if I had time.
Me too, I guess. But there is a second prong to this issue: where to the symbol definitions used to control the preprocessor come *from*? Or is that also addressed by the hmake code? #g ------------ Graham Klyne For email: http://www.ninebynine.org/#Contact

Graham Klyne wrote:
At 16:12 06/04/04 +0100, Malcolm Wallace wrote:
Much as we all hate cpp, I'm afraid the standard libraries are already heavily littered with #ifdefs. Getting rid of them is basically impossible. I guess it's the community's choice of what is important, but in my experience this is a major impediment to distributing portable programs written in Haskell for use by non-Haskellite end users.
Malcolm only pointed out that it is basically impossible to *implement* the libraries without #ifdefs due to the different capabilities and internal design choices of the Haskell systems. *Using* these libraries should of course be possible without reverting to CPP.
There should be no externally visible type differences in standard libraries. [...] So I would hope, but I seem to recall coming across some variations of function parameters between systems. I don't remember where.
That shouldn't be the case. I guess we still have some dark corners in the POSIX vs. non-POSIX area, suggestions for improving this (and other places, too, of course) are highly welcome. It would really be helpful to know what caused your grief... Cheers, S.

At 19:55 06/04/04 +0200, Sven Panne wrote:
Graham Klyne wrote:
At 16:12 06/04/04 +0100, Malcolm Wallace wrote:
Much as we all hate cpp, I'm afraid the standard libraries are already heavily littered with #ifdefs. Getting rid of them is basically impossible. I guess it's the community's choice of what is important, but in my experience this is a major impediment to distributing portable programs written in Haskell for use by non-Haskellite end users.
Malcolm only pointed out that it is basically impossible to *implement* the libraries without #ifdefs due to the different capabilities and internal design choices of the Haskell systems. *Using* these libraries should of course be possible without reverting to CPP.
The problem here is that, when using Hugs, the source code of the libraries needs to be part of the input to Hugs.
There should be no externally visible type differences in standard libraries. [...] So I would hope, but I seem to recall coming across some variations of function parameters between systems. I don't remember where.
That shouldn't be the case. I guess we still have some dark corners in the POSIX vs. non-POSIX area, suggestions for improving this (and other places, too, of course) are highly welcome. It would really be helpful to know what caused your grief...
If I rediscover it, I'll send a note to this list. #g ------------ Graham Klyne For email: http://www.ninebynine.org/#Contact

Malcolm Wallace
Graham Klyne
writes: Please, no #ifdef's in standard library code!
:)
Much as we all hate cpp, I'm afraid the standard libraries are already heavily littered with #ifdefs. Getting rid of them is basically impossible.
Perhaps we can work to slowly phase them out or confine them?
(d) For those differences that cannot be eliminated implementing (in Haskell) a portable preprocessor that can ship as part of every Haskell environment?
I think this is ultimately going to be the most viable solution. Let's write a simple 'hspp' (in Haskell?) that is backward compatible with 'cpp -traditional' (although we might also design a newer nicer syntax too), and distribute it with every compiler. It can't be too difficult, surely? Half of the cpp parsing/selection code is already available within hmake. I would take on the project myself, if I had time.
I agree that this should be possible with the hmake code. FWIW, I have, in fact, already teased that functionality out (to a small degree) and made it available in my work-in-progress HMake API. I expect that there would be a function Distribution.Build.cpp and needsCpp which are implemented in my HMake.hs code thusly:
-- |Does the source code represented by this string require C -- pre-processing? needsCpp :: String -> Bool needsCpp = GetDep.needsCpp
-- |Return just the list of lines that the real cpp would decide to keep. cpp :: FilePath -> SymTab String -> KeepState -> [String] -> [String] cpp = Imports.cpp
Eww, that cpp maybe uses unsafePerformIO? I can't remmeber. Anyway, if that's true, it's something we can fix. Graham is, of course, right that populating the SymTab now becomes the problem. I did write a little function to make this easier:
-- |Convert the environment to a SymTab. Don't know if this is -- actually useful, but it may simplify interface to cpp. envToSymTab :: [(String, String)] -- ^Environment -> SymTab String envToSymTab = foldr insertST emptyST
Anyway, take that for what it's worth. The HMake code is nice & clean, for the most part, and I'm working to refactor it to make its various bits of functionality available outside the executable itself. I plan to update this list on what I'm busy with on the LIP stuff Real Soon Now :) peace, isaac

Am Dienstag, 6. April 2004 20:13 schrieb Isaac Jones:
[...]
(d) For those differences that cannot be eliminated implementing (in Haskell) a portable preprocessor that can ship as part of every Haskell environment?
I think this is ultimately going to be the most viable solution. Let's write a simple 'hspp' (in Haskell?) that is backward compatible with 'cpp -traditional' (although we might also design a newer nicer syntax too), and distribute it with every compiler. It can't be too difficult, surely? Half of the cpp parsing/selection code is already available within hmake. I would take on the project myself, if I had time.
I agree that this should be possible with the hmake code. FWIW, I have, in fact, already teased that functionality out (to a small degree) and made it available in my work-in-progress HMake API.
Will such a preprocessor work on source code like cpp does or on a syntax tree? The latter would be better, IMO; the former would probably have little or no advantage over cpp. I
[...]
Wolfgang

Wolfgang Jeltsch
Am Dienstag, 6. April 2004 20:13 schrieb Isaac Jones:
[...]
(d) For those differences that cannot be eliminated implementing (in Haskell) a portable preprocessor that can ship as part of every Haskell environment?
I think this is ultimately going to be the most viable solution. Let's write a simple 'hspp' (in Haskell?) that is backward compatible with 'cpp -traditional' (although we might also design a newer nicer syntax too), and distribute it with every compiler. It can't be too difficult, surely? Half of the cpp parsing/selection code is already available within hmake. I would take on the project myself, if I had time.
I agree that this should be possible with the hmake code. FWIW, I have, in fact, already teased that functionality out (to a small degree) and made it available in my work-in-progress HMake API.
Will such a preprocessor work on source code like cpp does or on a syntax tree?
On source code, at least for now. There's no plan, ATM, to include a parser with Distribution.Build. It could be useful, but I expect that we want to pass such work onto the compilers / interpreters. Can you explain the syntax tree you picture for this? Where will such a tree come from?
The latter would be better,
Why?
IMO; the former would probably have little or no advantage over cpp.
From the point of view of this conversation, the advantage would be that it's implemented in pure Haskell, so you don't need external tools that may be difficult to get on your system.
The reason it's there in Distribution.Build is so that wrapper build systems (whether they be implemented in Make or in Haskell) can utilize a common interface. peace, isaac

Am Dienstag, 6. April 2004 20:36 schrieben Sie:
[...]
Will such a preprocessor work on source code like cpp does or on a syntax tree?
On source code, at least for now. There's no plan, ATM, to include a parser with Distribution.Build. It could be useful, but I expect that we want to pass such work onto the compilers / interpreters.
Can you explain the syntax tree you picture for this? Where will such a tree come from?
I have no detailed picture at the moment.
The latter would be better,
Why?
Look at XML. You are able to include XML code from other files but the code you import must be a complete XML element. Similarily, the brances of a Haskell #ifdef should be producable out of a non-terminal, and, more specific, they should be producable out of the same non-terminal. With these restrictions, one would be able to guarantee syntactical correctness without evaluating the #ifdef conditions, for example.
[...]
Wolfgang

On Tue, 2004-04-06 at 12:05, Wolfgang Jeltsch wrote:
Look at XML. You are able to include XML code from other files but the code you import must be a complete XML element. Similarily, the brances of a Haskell #ifdef should be producable out of a non-terminal, and, more specific, they should be producable out of the same non-terminal. With these restrictions, one would be able to guarantee syntactical correctness without evaluating the #ifdef conditions, for example.
This doesn't work for one possible (and, I expect, common) use of a preprocessor -- if one of the branches is syntactically incorrect for some compilers. For instance, perhaps one branch uses the GHC unboxed values extensions for performance, and the other branch uses H98 for portability. I think that the best approach for dealing with the current libraries (and the issues of using them under Windows, where you might not have a convenient CPP) is the same approach others are advocating -- implement a CPP-compatible preprocessor in Haskell, and ship it with the various systems. On the other hand, if you want to design a new preprocessor that works better with Haskell, I highly recommend reading Keith Wansbrough's unpublished paper, Macros and Preprocessing in Haskell (available from http://www.cl.cam.ac.uk/users/kw217/research/paper-abstracts.html). Carl Witty

Am Dienstag, 6. April 2004 23:13 schrieb Carl Witty:
On Tue, 2004-04-06 at 12:05, Wolfgang Jeltsch wrote:
Look at XML. You are able to include XML code from other files but the code you import must be a complete XML element. Similarily, the brances of a Haskell #ifdef should be producable out of a non-terminal, and, more specific, they should be producable out of the same non-terminal. With these restrictions, one would be able to guarantee syntactical correctness without evaluating the #ifdef conditions, for example.
This doesn't work for one possible (and, I expect, common) use of a preprocessor -- if one of the branches is syntactically incorrect for some compilers. For instance, perhaps one branch uses the GHC unboxed values extensions for performance, and the other branch uses H98 for portability.
Well, the preprocessor would have to be able to parse all extensions. Maybe this is too difficult.
[...]
Wolfgang

At 20:18 06/04/04 +0200, Wolfgang Jeltsch wrote:
I agree that this should be possible with the hmake code. FWIW, I have, in fact, already teased that functionality out (to a small degree) and made it available in my work-in-progress HMake API.
Will such a preprocessor work on source code like cpp does or on a syntax tree? The latter would be better, IMO; the former would probably have little or no advantage over cpp.
The key advantage over CPP is that it's available wherever a Haskell system is installed. The tools you take for granted on Unix/Linux are not always installed on (say) Windows target systems. My goal here is that Haskell programs be easy to use on any target. Installing a Haskell system may be too much overhead, but we can't get away without that. Anything else is an unnecessary barrier to adoption. #g ------------ Graham Klyne For email: http://www.ninebynine.org/#Contact

Will such a preprocessor work on source code like cpp does or on a syntax tree? The latter would be better, IMO; the former would probably have little or no advantage over cpp.
A bunch of people have answered this already but your comment reminded me of one of the cpp problems we might want to avoid (by omitting a large chunk of cpp functionality). One of cpp's flaws is that it has absolutely no notion of scope so if you define a macro 'bar' then code like this can do surprising things. foo bar = baz What do people use macros for? 1) Aliases and abstraction: Macros are useful in C because C is quite poor at defining aliases for existing things. (e.g., typedefs can't be parameterized, you can't define an alias for a variable, creating an alias for a function is expensive unless you (can) mark it inline). Haskell has great ways of creating aliases for things: type synonyms and function definitions. There's no strong need for more. (A few exceptions listed at the end of this mail.) 2) Defining symbols to be used in #ifs This is useful for conditional compilation in both C and Haskell. So, I'd like to float the idea that the Haskell preprocessor should _only_ support conditional compilation, that macro expansion should only occur in lines that begin with '#' not in "normal" lines and that macros should always evaluate to expressions with simple scalar types (ints, strings, etc.) Similarly, I'd like to drop token splicing (e.g., foo##bar in ANSI C or foo/**/bar in K&R C). It's mostly useful for overcoming limitations in C and isn't much used to help you write #ifs. These two changes make it possible to replace the usual horrible mix of macro expansion, parsing and evaluation with a conventional interpreter. #defines assign values to variables and #if evaluates expressions involving those 'variables'. I'm not sure if it would still be useful to be able to define parameterized macros like #define max(x,y) ... but I doubt it would cost much to allow it. Advantages: 1) hspp implementation is a lot simpler. [It's probably simple enough that the preprocessor could easily be built into Hugs if we wanted. This isn't the primary motivation for this suggestion but it would be nice.] 2) hspp semantics easier to understand so programmers not caught out by name capture and all the other problems that cpp can cause. 3) hspp only affects lines that start with # in the first column. This further lessens chance of programmer being caught out. 4) No need to add extra parentheses round every use of a macro argument and round macro bodies as in: #define max(x,y) ((x)>(y)?(x):(y)) There's only one place I know of where this restriction would have any significant effect. The FFI libraries have a lot of very similar definitions for all the new FFI types to define the Storable instances. IIRC, a cpp macro is used to significantly reduce the amount of code that has to be written and to make it easier to read/maintain. It would be a shame to lose this use of cpp but, if this is the only loss, I think it would be worth it. -- Alastair Reid www.reid-consulting-uk.ltd.uk ps Inessential syntax tweak: If we are willing to change cpp syntax instead of just restricting it, we might require "=" between the lhs and rhs of a macro definition. This makes parsing of macros a little easier. cpp macros are a bit funny in that you get very different results if you write a space between the macro name and the arguments. For example: #define max(x,y) x>y?x:y and #define max (x,y) x>y?x:y The first is a parameterized macro, the other isn't. With this change, the following would be equivalent. #define max(x,y) = x>y?x:y and #define max (x,y) = x>y?x:y

Alastair Reid wrote:
So, I'd like to float the idea that the Haskell preprocessor should _only_ support conditional compilation, that macro expansion should only occur in lines that begin with '#' not in "normal" lines and that macros should always evaluate to expressions with simple scalar types (ints, strings, etc.)
[It's probably simple enough that the preprocessor could easily be built into Hugs if we wanted. This isn't the primary motivation for this suggestion but it would be nice.]
I'd vote for that (as a user). If we absolutely need preprocessing, then the above looks like a very reasonable way to go: 1. keep it simple, 2. integrate it with compilers. best regards, -- -- Johannes Waldmann, Tel/Fax: (0341) 3076 6479 / 6480 -- ------ http://www.imn.htwk-leipzig.de/~waldmann/ ---------

Alastair Reid wrote:
What do people use macros for? 1) Aliases and abstraction: [...] 2) Defining symbols to be used in #ifs [...]
Nice summary, but I'd like to add two more points here: 3) Syntactic abstraction One example you've already mentioned are the macros for Storable, another one is from my OpenGL package: http://cvs.haskell.org/cgi-bin/cvsweb.cgi/fptools/libraries/OpenGL/include/HsOpenGLExt.h?rev=1.5&content-type=text/x-cvsweb-markup This macro allows me to define an OpenGL extension function in a very handy way: EXTENSION_ENTRY("GL_EXT_fog_coord or OpenGL 1.4",glFogCoorddEXT,GLdouble -> IO ()) The actual implementation is hidden here, and I can simply use glFogCoorddEXT as if it was a normal OpenGL function. (For OpenGL aficionados: Later I'd like to implement per-context extension entries, and having the mechanics concentrated in a single place is a *big* win.) It's not that I'm very proud of this tricky macro, but Haskell simply doesn't allow this kind of abstraction. 4) Annoying FFI differences Because WinDoze folks decided to have a different calling convention for DLLs than the rest of the world, one has to use "stdcall" instead of "ccall" in FFI imports from time to time. The easiest way to handle this is via a simple macro CALLCONV: foreign import CALLCONV "foo" foo :: IO () I really urge people proposing simple solutions for the CPP problem to try their proposals on non-toy examples. "Keep it simple. But not too simple." Cheers, S.

Another reason for using cpp -traditional (or a clone thereof) is that it hooks in to autoconf. Now autoconf is pretty ugly inside, but the problem it solves is messy indeed, and someone else has already done it. It's best treated as a black box, and not one we want to re-invent. (Which is another argument for a prosaic clone of cpp -traditional)

I wrote:
Half of the cpp parsing/selection code is already available within hmake. I would take on the project myself, if I had time.
OK, that was a fatal statement on my part I fear.... I have hacked on the hmake code a bit today, and can now announce the first release of: cpphs 0.1 a standalone replacement for cpp, written in Haskell'98 http://www.cs.york.ac.uk/fp/cpphs Needless to say, it doesn't do everything you would want yet. In summary, it can cope with conditionals and inclusion, but not parametrised macro expansion. This is definitely prototype code, so please try it out and report any bugs. Suggestions for a better name, and for positioning of the worker modules in the hierarchical libraries would be welcome. We can think about putting it in CVS and getting compilers to use it at a later date. Here is an excerpt from the README: USAGE ----- cpphs [ filename | -Dsym | -Dsym=val | -Ipath ]+ You can give any number of filenames on the command-line. The results are catenated on standard output. Options: -Dsym define a symbol -Dsym=val define a symbol with a specific value -Ipath add a directory to the search path for #include's There are NO symbols defined by default. Could easily be changed in the source code though. The search path is searched in order of the -I options, except that the current directory is always searched first. Features that do work: #ifdef simple conditional compilation #if the full boolean language of defined(), &&, ||, ==, etc. #elif chained conditionals #define in-line definitions (symbols only, not macros) #undef in-line revocation of definitions #include file inclusion #line line number directives Numbering of lines in the output is preserved so that any later processor can give meaningful error messages. When a file is #include'd, cpphs inserts #line directives for the same reason. Any syntax errors in cpp directives, and any failure to find a #include'd file, gives a message to standard error and halts the program. Features that don't work: #define parametrised macro definitions \ especially those that extend over several lines with line continuation characters Regards, Malcolm

At 18:11 07/04/04 +0100, Malcolm Wallace wrote:
I wrote:
Half of the cpp parsing/selection code is already available within hmake. I would take on the project myself, if I had time.
OK, that was a fatal statement on my part I fear.... I have hacked on the hmake code a bit today, and can now announce the first release of:
I just checked it out with Hugs under Windows, and it seems (mostly) OK. The only oddity I noticed was an extra '/' in a #line directive for an included file: [[ #line 1 "tests//inclusion" hello world, this is an inclusion #line 21 "tests/testfile" ]] -- http://www.ninebynine.org/Software/HaskellUtils/cpphs/tests/expectfile3 ... I've hacked the main program module to include an HUnit test based on your test files, which can be run interactively from Hugs, thus: [[ Main> run allTests Cases: 3 Tried: 3 Errors: 0 Failures: 0 Main> ]] The main program function itself is not affected (though I've split it into two parts). The modifications are available here: http://www.ninebynine.org/Software/HaskellUtils/cpphs/cpphs.hs (The unit tests could easily enough be split into a separate file) The tests directory also contains 3 additional files with the expected results of the three test cases created: http://www.ninebynine.org/Software/HaskellUtils/cpphs/tests/ (resultfile is a temporary file created by the test case logic.) #g ------------ Graham Klyne For email: http://www.ninebynine.org/#Contact

Graham Klyne wrote:
Please, no #ifdef's in standard library code! [...]
You're totally right, and I wouldn't propose this under normal circumstances, but in this special case it would be harmless: The #ifdefs would only exclude the import of Data.Monoid and a few instances of Monoid. So we have two cases to consider: a) The Haskell system in question supports Data.Monoid, so nothing would be excluded and all is well as before. b) Data.Monoid is not supported, so having no instances for Monoid would be a rather void statement here. :-) Either way, Ross has proposed a tiny change to make Data.Monoid portable, which would avoid the #ifdef problem altogether. Cheers, S.
participants (18)
-
ajb@spamcop.net
-
Alastair Reid
-
Carl Witty
-
Daan Leijen
-
dpt@lotus.bostoncoop.net
-
Graham Klyne
-
Graham Klyne
-
Iavor S. Diatchki
-
Isaac Jones
-
Johannes Waldmann
-
JP Bernardy
-
Malcolm Wallace
-
Manuel M T Chakravarty
-
Robert Will
-
Ross Paterson
-
ross@soi.city.ac.uk
-
Sven Panne
-
Wolfgang Jeltsch