You can do this with Template Haskell, which is technically yet another GHC extension, but is probably somehow more "pure" than C preprocessor.
Code stolen from here and modified slightly.
{-# LANGUAGE TemplateHaskell #-}
module WithLocation (withLocation) where
import Language.Haskell.TH
withLocation' :: String -> IO a -> IO a
withLocation' s f = do { putStrLn s ; f }
withLocation :: Q Exp
withLocation = withFileLine [| withLocation' |]
withFileLine :: Q Exp -> Q Exp
withFileLine f = do
let loc = fileLine =<< location
appE f loc
fileLine :: Loc -> Q Exp
fileLine loc = do
let floc = formatLoc loc
[| $(litE $ stringL floc) |]
formatLoc :: Loc -> String
formatLoc loc = let file = loc_filename loc
(line, col) = loc_start loc
in concat [file, ":", show line, ":", show col]
Use it like this (from another module):
{-# LANGUAGE TemplateHaskell #-}
module Main where
import WithLocation
main = do
$withLocation $ putStrLn "===oo0=Ü=0oo=== Kilroy was here"