Subscribe to
Posts
Comments

Riddle me this

I find Lennart Augustsson's Text.Printf module very handy, but also quite baffling.

Here is one example of my bafflement: suppose I want to print a piece of text if my program's verbosity level is above a certain threshold, but not otherwise. I'd like to hide that detail in a function, such that I could just call something like this:

 note cfg "mean is %s (%d iterations)\n" (secs µ) iters

and my note function would Do The Right Thing. The type signature of hPrintf seems to make this impossible to do elegantly, since the number of arguments to note is not clear. Hence a fugly hack:

nullDev :: Handle
nullDev = unsafePerformIO $ openBinaryFile "/dev/null" WriteMode
{-# NOINLINE nullDev #-}

note :: (HPrintfType r) => Config -> String -> r
note cfg msg = if cfgVerbosity cfg > Quiet
               then hPrintf stdout msg
               else hPrintf nullDev msg

This makes me a sad Irish panda.

The next thing I'd like to be able to do, and over which I am also baffled, is to hide that Config parameter, since it's ubiquitous in my code:

newtype Criterion a = Criterion (ReaderT Config IO a)
    deriving (Monad, MonadReader Config, MonadIO)

Most of the time, I can ask for the current Config when I need to. However, when it comes to eliminating this parameter from my note function, I am once again stymied by the type of hPrintf, since there's no way to tell what monad I'm living in.

Help!

6 Responses to “Riddle me this”

  1. on 25 Sep 2009 at 15:51sclv

    this is a terrible hack, but no more of a hack than printf itself:

    test :: (HPrintfType r, NoOp r) => Bool -> Handle -> String -> r
    test b = if b then hPrintf
    else nopr

    class NoOp a where
    nopr :: a

    instance NoOp (IO a) where
    nopr = return undefined

    instance (NoOp r) => NoOp (a -> r) where
    nopr = const $ nopr

    don’t have an answer for the second bit at the moment tho.

  2. on 26 Sep 2009 at 00:09brian

    Don’t forget package ‘xformat’.

  3. on 26 Sep 2009 at 00:38Saizan

    I got a solution requiring more extensions but that it looks more general, here’s the paste:
    http://hpaste.org/fastcgi/hpaste.fcgi/view?id=9857

    The types, especially those inferred like in test, aren’t so pretty but not horrible either.

  4. on 26 Sep 2009 at 12:40Bryan O'Sullivan

    Saizan: Wow, that’s impressive. Type signatures longer than the code they describe? Eeek!

  5. on 26 Sep 2009 at 12:46Saizan

    well, the typeclass system is what’s doing most of the work :P

  6. [...] little while ago, Bryan O’Sullivan was developing his Criterion benchmark suite, and had trouble with using the Text.Printf module in a monad transformer on top of IO. I thought I knew how to solve this, but my first idea didn’t work — and nor did my [...]

Leave a Reply