syntax...(strings/interpolation/here docs)
C.Reinke
C.Reinke@ukc.ac.uk
Wed, 13 Feb 2002 14:36:01 +0000
> > 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