With {-# LANGUAGE CPP #-} enabled, .hs files will be processed with C preprocessor before the code is compiled. It's often useful if:

you need backwards compatibility with an older version of GHC or some library, or you want to avoid compiler warnings

you are writing code that depends on OS or CPU architecture

you want to enable some parts of code depending on a flag

you don't want to bother with Template Haskell and need some easy way to generate code (e.g. repetitive instances)

However, see the Stop (ab)using CPP in Haskell sources post for a discussion of some drawbacks of CPP (and alternatives to it).

Running CPP

To dump CPP output, do ghc -E file.hs (it'll be saved into file.hspp ). There might be a lot of empty lines in the file, so don't forget to scroll.

To just run CPP on a file without using GHC, do either of these:

gcc -E -traditional - < file.hs (on Linux)

(on Linux) clang -E -traditional - < file.hs (on macOS)

(on macOS) cpphs file.hs (for cpphs)

Since Clang is used instead of GCC on macOS, and Clang's preprocessor syntax is slightly different, you should use this command to see whether your code would compile under Clang:

$ ghc -pgmP "clang -E -undef -traditional" file.hs

CPP features

Defining macros

#define DOUBLE_QUOTE 34 #define POW(a,b) a ^ (b :: Int)

Once a constant/macro is defined, it'll be substituted everywhere in code (except when it's a part of a string or a word). For instance, POW(2,3) will be replaced with 2 ^ (3 :: Int) .

Using constants as flags

#ifdef FOO /* or #ifndef to check that a constant is *not* defined */ ... #endif

Code inside #ifdef ... #endif will be removed unless FOO is defined (which can be done via .cabal or with a #define earlier in the file).

Conditionals

#if __GLASGOW_HASKELL__ < 710 ... #endif

#ifdef FOO is actually a shortcut for #if defined(FOO) ; with #if you can branch on an arbitrary boolean expression (see the GCC manual for full syntax of conditionals). Also, you can have more than two branches with #elif . Note that #define and other CPP directives can be used inside of #if – it's useful when you're writing your own macros.

See the “Standard CPP macros” section in the GHC manual for a full list of macros defined by GHC.

Tricks

Commas

If you need to use a comma in a macro argument, just define a separate macro for the comma:

#define COMMA , GEN(a COMMA b COMMA c)

Concatenation

If CPP doesn't understand that a macro should be expanded in some particular place (e.g. if it's a part of a word, or has _ in front of it, etc), you can use /**/ :

#define U(x) xbar U(foo) <- expanded into “xbar”

#define U(x) x /**/ bar U(foo) <- expanded into “foobar” on GCC or “foo bar” on Clang

Note that if you don't want a space there, cpphs is your only bet.

Workarounds

There are three main reasons why code with CPP might not work as expected: