Showing posts with label preprocessor. Show all posts
Showing posts with label preprocessor. Show all posts

Wednesday, October 6, 2010

Verbose show and the missing preprocessor

Verbose show

Say we want a function vshow which describes an expression before showing its value. For example:

vshow (2 + 3)          = "2 + 3 = 5"
vshow (product [1..5]) = "product [1..5] = 120"

Clearly vshow can't be an ordinary Haskell function. We just don't have that kind of runtime access to program source.

All sorts of workarounds come to mind: simple-reflect, feeding strings to hint, Template Haskell… But it's hard to beat the simplicity of the humble C preprocessor:

{-# LANGUAGE CPP #-}
{-# OPTIONS_GHC -pgmP cpp #-}

#define vshow(e) (#e ++ " = " ++ show (e))

main :: IO ()
main = do
putStrLn vshow(2 + 3)
putStrLn vshow(product [1..5])

GHC's built-in CPP can't handle the stringify operator, so we invoke the "real" C preprocessor with -pgmP cpp. Testing it:

$ runhaskell vshow.hs
2 + 3 = 5
product [1..5] = 120

Like the other solutions I mentioned, this has its drawbacks. vshow isn't a first-class function, and we have to use C rather than Haskell function-call syntax. It's not terribly flexible, but it is one line of reasonably clear code, and I can think of a few small use cases.

The missing preprocessor

Besides sharing a cute little trick, I wanted to start a conversation about text-level preprocessors for Haskell. CPP is used throughout the standard library for conditional compilation, boilerplate class instances, etc. At the same time, it's quite limited, and not a good syntactic fit for Haskell.

Template Haskell is at the opposite end of the power/complexity spectrum. It might be what you want for programmatically generating complicated abstract syntax trees. It's not a good fit for simply "copy-pasting" some text into a few locations. For those tasks we shy away from the enormous complexity of TH. We use CPP or, well, copy-paste. The latter is not acceptable for a language that's advertising such a high level of abstraction. We may write less boilerplate than in Java or C++, but it still gets on the nerves.

I think there's an unfilled niche for lightweight text-level preprocessing, with just a bit more flexibility than CPP. GHC makes it easy to plug in any preprocessor you like, using -F -pgmF. We can start experimenting today.

m4 is a powerful and venerable preprocessor. It comes with most UNIX systems and has an open-source implementation. Yet I've not seen any Haskell project use it for Haskell source. Has anyone used m4 in this role?

I found an old paper (.ps.gz) with some proposals. Anyone have comments?

There's a number of preprocessors for implementing specific language features, including arrows, indexed monads, C bindings, and Conor McBride's intriguing Strathclyde Haskell Enhancement. The package preprocessor-tools seems to be a framework for writing this sort of preprocessor.

So what have you used for preprocessing? What features would you like to see? What design philosophy?