
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