12

Is it possible to use CPP extension on Haskell code which contains multiline string literals? Are there other conditional compilation techniques for Haskell?

For example, let's take this code:

-- If the next line is uncommented, the program does not compile.
-- {-# LANGUAGE CPP #-}

msg = "Hello\
  \ Wor\
  \ld!"

main = putStrLn msg

If I uncomment {-# LANGUAGE CPP #-}, then GHC refutes this code with a lexical error:

[1 of 1] Compiling Main             ( cpp-multiline.hs, cpp-multiline.o )

cpp-multiline.hs:4:17:
    lexical error in string/character literal at character 'o'

Using GHC 6.12.1, cpphs is available.

I confirm that using cpphs.compat wrapper and -pgmP cpphs.compat option helps, but I'd like to have a solution which does not depend on custom shell scripts. -pgmP cpphs does not work.

P.S. I need to use different code for GHC < 6.12 and GHC >= 6.12, is it possible without preprocessor?

UPD. In addition to the accepted answer of Ganesh, I also found that another workaround is to put all conditional declarations in a separate module with {-# LANGUAGE CPP #-} and thus avoid CPP in the modules with multiline strings.

sastanin
  • 40,473
  • 13
  • 103
  • 130
  • Why not use `"Hello" ++ " Wor" ++ "ld!"`? – kennytm Mar 31 '10 at 12:58
  • Because `"Hello\ whitespace+ \ World!"` is Haskell 98. Because there is some code around which uses it. Because `" ++ "` takes more space (and I dislike code beyond 80 columns). And finally, I'd like to write a patch without re-wrapping and re-formatting every multiline string in the project. – sastanin Mar 31 '10 at 14:00

2 Answers2

6

cpphs now has a --cpp option itself, which I think makes the compat script unnecessary: see the cpphs 1.3 entry at http://haskell.org/cpphs/

I think you'd need to pass -optP --cpp to GHC (as well as -pgmP cpphs) to enable this behaviour.

Ganesh Sittampalam
  • 28,821
  • 4
  • 79
  • 98
2

It seems the GHC user manual addresses this: Section 4.10.3.1 reads

A small word of warning: -cpp is not friendly to “string gaps”.. In other words, strings such as the following:

strmod = "\
\ p \
\ "

don't work with -cpp; /usr/bin/cpp elides the backslash-newline pairs.

However, it appears that if you add a space at the end of the line, then cpp (at least GNU cpp and possibly other cpps) leaves the backslash-space pairs alone and the string gap works as expected.

Reid Barton
  • 14,951
  • 3
  • 39
  • 49
  • Thank you. I tried to add trailing spaces after \, but cpp just reports a warning `backslash and newline separated by space`, and the code still does not compile. Using GNU cpp 4.4.3. – sastanin Mar 31 '10 at 09:06