Re: syntax...(strings/interpolation/here docs)

Does anybody with their elbows in the code think variable interpolation and/or multi-line strings are good/doable ideas? Would this be the sort of change one could make without a lot of previous familiarity with the implementation of Hugs/Ghc?
Unlike my rough proposal, one should aim for a combination of (mostly) in-Haskell implementation and (some) pre-processing. As Thomas Nordin has pointed out to me in private email, Hugs (Dec 2001) already supports this (module lib/hugs/Quote.hs and flag +H). The real trick is to have the same support in all implementations..
I don't think it is really necessary to add the feature to the language, since you can program something very similar for yourself in user-code.
It is not really necessary, but "very similar" isn't good enough for the purpose (see further down). - haven't tried with other systems, but Hugs at least has some limit on maximum token length (4000). This is a lot easier to avoid if string variable interpolation implicitly breaks up tokens. - I've tried to work with Haskell's \\-multiline strings - I don't find them useable. The extra characters at the end and start of lines make them less readable and less writeable than necessary for this kind of applications (my current workaround is to use break strings on lines, either with explicit concatenation or with lists of strings and the good old unlines to get rid of those "\n"s) - as said above, I do agree that there should be no complex language extensions for what can be done in Haskell, and Hugs' combination of Quote module and +H support gets close to that. If you have to change string quoting (to preserve formatting), you might as well throw in variable interpolation (only needs "..$(var).." -> ".."++quote var++"..", the rest is Haskell code). It is similar to what I posted, but the ``$(var) $$''-syntax is simpler, there are no overlapping instances, and there is an explicit function to trim leading whitespace instead of the extra layout rule I assumed. Here's your example, with Hugs' Quote: {- :set +H -} import Quote hereDocument v w = ``Multi-line string starts here and uses string gap delimiters. Variable names like $(a) are filled in from the bindings specified in the `with` clause, e.g. $(a) = $$a, $(b) = $$b and unused bindings pass through e.g. $(c) = $$c.'' where (a,b,c) = (v,w,"$c") After all, the purpose of here-documents is readability in programs that have to generate programs or formatted text (e.g., the popular Haskell/CGI libraries, or libraries generating XML/HTML/VRML/SVG/..). In those contexts, they are an important matter of convenience - you just write the text template you want to generate, filled in with variables. Meta-programming is difficult enough without asking for trouble (extra \ everywhere, explicit \n, by hand conversion from any type a to String, no checks of variable bindings instead of lexical scoping). The only disadvantage I've seen so far (apart from that maximum token length..) is the need to disambiguate numeric types for the overloaded quote, but that's a standard Haskell problem. Claus
Here's a sample of a single-character macro expansion within strings, that took a couple of minutes to write.
module Printf where import Maybe(fromMaybe)
hereDocument :: (Show a, Show b) => a -> b -> String hereDocument v w = "Multi-line string starts here\ \ and uses string gap delimiters.\n\ \ Variable names like $$a are filled in from the\n\ \ bindings specified in the `with` clause,\n\ \ e.g. $$a = $a, $$b = $b\n\ \ and unused bindings pass through e.g. $$c = $c." `with` [('a',show v), ('b',show w)]
with :: String -> [(Char,String)] -> String [] `with` env = [] ('$':'$':cs) `with` env = '$': cs `with` env ('$':c:cs) `with` env = s ++ cs `with` env where s = fromMaybe ('$':c:[]) (lookup c env) (c:cs) `with` env = c : cs `with` env

On Wednesday 13 February 2002 06:36 am, C.Reinke wrote:
Does anybody with their elbows in the code think variable interpolation and/or multi-line strings are good/doable ideas? Would this be the sort of change one could make without a lot of previous familiarity with the implementation of Hugs/Ghc?
Unlike my rough proposal, one should aim for a combination of (mostly) in-Haskell implementation and (some) pre-processing. As Thomas Nordin has pointed out to me in private email, Hugs (Dec 2001) already supports this (module lib/hugs/Quote.hs and flag +H).
The real trick is to have the same support in all implementations..
I use here docs quite a bit. They are wonderful for writing error messages that are also readable in the code ;-) The point about same support in all implementations is of course a good one. Thomas and I are the culprits who put here docs in hugs in the first place. However, it is just as easy to support here docs using a pre-processor. I have a medium sized project that uses here docs, and can be used under both hugs and ghc. With hugs, I use the builtin feature, of course. With GHC, we just use a pre-processor. This is a bit awkward with GHC 5.02 and earlier versions, but starting with 5.03, GHC now has a proper interface for hooking in a pre-processor (don't know the details, bug Sigbjorn says it's in there). A convenient feature of here docs that makes it easy to implement as a pre-processor is that you can do the unhere doc translation so that it preserves line numbers. The only drawback to using a pre-processor is that it probably won't work with ghci (but then you probably don't need to write here docs at the command line either!). --Jeff

hugs and ghc. With hugs, I use the builtin feature, of course. With GHC, we just use a pre-processor. This is a bit awkward with GHC 5.02 and earlier versions, but starting with 5.03, GHC now has a proper interface for hooking in a pre-processor (don't know the details, bug Sigbjorn says it's in there).
Is this true? Is there any documentation on it?

On Wed, Feb 13, 2002 at 08:42:09AM -0800, Jeffrey R Lewis wrote:
The point about same support in all implementations is of course a good one. Thomas and I are the culprits who put here docs in hugs in the first place. However, it is just as easy to support here docs using a pre-processor. I have a medium sized project that uses here docs, and can be used under both hugs and ghc. With hugs, I use the builtin feature, of course. With GHC, we just use a pre-processor. This is a bit awkward with GHC 5.02 and earlier versions, but starting with 5.03, GHC now has a proper interface for hooking in a pre-processor (don't know the details, bug Sigbjorn says it's in there).
That would be -F/-pgmF/-optF (they're documented). OK, some Haskell extensions can be implemented using preprocessors. It's imperfect (errors in the output hard to trace back to the source, errors in the preprocessor hard to handle properly) but it's better than nothing. But what's the best way to manage this? Suppose you have several modules, some of which need no preprocessor, while others need to be preprocessed in different ways (ignoring multiple extensions -- too hard). I've been doing this by using different filename extensions to distinguish them, plus a patched version of Hugs that can be told what filename extensions to accept, plus a preprocessor that uses the filename extensions to decide what to do. (For example, .y files could be sent through happy.) An alternative might be options in the source files, though the new GHC options are static, so that's not supported.

But what's the best way to manage this? Suppose you have several modules, some of which need no preprocessor, while others need to be preprocessed in different ways (ignoring multiple extensions -- too hard). I've been doing this by using different filename extensions to distinguish them, plus a patched version of Hugs that can be told what filename extensions to accept, plus a preprocessor that uses the filename extensions to decide what to do. (For example, .y files could be sent through happy.)
The latest version of hmake (3.01) has support for calling a preprocessor based on the filename extension, before calling the compiler on the resulting file. Currently, it recognises: .y Happy .ly literate Happy .gc GreenCard .hsc hsc2hs .chs C->HS .hs.cpp C preprocessor I'm not really sure whether the invocation magic for all of these is correct yet, but I would encourage people to try it out and send patches. It is pretty easy to add new preprocessors - there are basically four options to define for each pp in addition to the filename extension. Regards, Malcolm

On Fri, Feb 15, 2002 at 11:27:05AM +0000, Malcolm Wallace wrote:
The latest version of hmake (3.01) has support for calling a preprocessor based on the filename extension, before calling the compiler on the resulting file. Currently, it recognises:
.y Happy .ly literate Happy .gc GreenCard .hsc hsc2hs .chs C->HS .hs.cpp C preprocessor
I'm not really sure whether the invocation magic for all of these is correct yet, but I would encourage people to try it out and send patches. It is pretty easy to add new preprocessors - there are basically four options to define for each pp in addition to the filename extension.
That's nice. Is it user-configurable? (i.e. without changing the compiler)

The latest version of hmake (3.01) has support for calling a preprocessor based on the filename extension,
That's nice. Is it user-configurable? (i.e. without changing the compiler)
At the moment, the list of preprocessors is coded into hmake (not the compiler). The main reason for not storing it in an editable configuration file is because some of the options are functions, which don't readily lend themselves to Show and Read instances... However, like I said, there isn't much to it - anyone could edit the sources to add 5 lines for their favorite preprocessor. And I'm sure if user-configurability turns out to be a much-desired feature, we can recode the functional options somehow to be able to read them from a config file. Regards, Malcolm
participants (5)
-
C.Reinke
-
Hal Daume III
-
Jeffrey R Lewis
-
Malcolm Wallace
-
Ross Paterson