
I'm writing code with hslogger, and I'm finding myself frequently
writing things like this:
infoM $ printf "%s saw %s with %s" (show x) (show y) (show z)
On #haskell I asked about why you can't have use %s with any instance
of (Show a), and augustss, the Text.Printf maintainer, pointed out
that it's not possible in Haskell 98 because of overlapping instances.
So I'm trying to figure out the best way to work around this in my
code. Some of the logging statements can get kind of long, so the
ability to elide the calls to `show` would be nice. So what's the best
way to do this?
I was thinking of making my own variant of printf that only accepted
the %s formatter and took (Show a)'s as arguments, but there might be
a simpler way? Another thing is the code is already fairly GHC
specific at this point, so if there are GHC extensions that might be
useful here that I don't know about, I'm interested in hearing about
them.
Thanks.
--
Evan Klitzke

You can use CPS printf, which has the advantage of being completely type-safe:
lit :: String -> (String -> r) -> r lit s k = k s
str :: (String -> r) -> (String -> r) str k s = k s
val :: Show a => (String -> r) -> a -> r val k a = k (show a)
(^) :: ((String -> r) -> s) -> ((String -> s) -> t) -> ((String -> r) -> t) (a ^ b) k = b $ \s -> a $ \t -> k (s ++ t)
cprintf :: ((String -> String) -> s) -> s cprintf k = k id
ghci> :t cprintf (val ^ lit "a" ^ val)
cprintf (val ^ lit "a" ^ val) :: (Show a, Show a1) => a1 -> a -> [Char]
ghci> putStrLn $ cprintf (val ^ lit "a" ^ val) 5 ()
5a()
This can be improved further by using difference lists instead of
Strings as the carrier type, to avoid bad behavior in ++, but it's
good enough for most uses.
It's definitely more wordy than the raw printf, but you can use
Template Haskell to build real printf out of it:
ghci> putStrLn $ $(sprintf "%va%v") 5 ()
5a()
Doing so is kind of fun, so I'll leave it as an exercise :)
-- ryan
On Thu, Jun 4, 2009 at 12:41 AM, Evan Klitzke
I'm writing code with hslogger, and I'm finding myself frequently writing things like this:
infoM $ printf "%s saw %s with %s" (show x) (show y) (show z)
On #haskell I asked about why you can't have use %s with any instance of (Show a), and augustss, the Text.Printf maintainer, pointed out that it's not possible in Haskell 98 because of overlapping instances. So I'm trying to figure out the best way to work around this in my code. Some of the logging statements can get kind of long, so the ability to elide the calls to `show` would be nice. So what's the best way to do this?
I was thinking of making my own variant of printf that only accepted the %s formatter and took (Show a)'s as arguments, but there might be a simpler way? Another thing is the code is already fairly GHC specific at this point, so if there are GHC extensions that might be useful here that I don't know about, I'm interested in hearing about them.
Thanks.
-- Evan Klitzke
:wq _______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe
participants (2)
-
Evan Klitzke
-
Ryan Ingram