Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

function composition with Text.Printf.printf

I would like to define a logger function, like

myPutStrLn = putStrLn . (++) "log: "
main = do myPutStrLn "hello"

which is fine. Now I want to format the provided String with printf, like this

myPutStrLn $ printf "test %d" (23 :: Int)

Great! Since I have this pattern very often I want to factor printf into the logger function:

myPrintf = logger . printf
  where
    -- note, this is just an example. should be
    -- replaceable with any function with this
    -- typesignature
    logger :: String -> IO ()
    logger = putStrLn . (++) "log: "

main = myPrintf "test %d" (23 :: Int)

Unfortunately, this fails with

The function `myPrintf' is applied to two arguments,
but its type `String -> IO ()' has only one
In a stmt of a 'do' block: myPrintf "test %d" (23 :: Int)
In the expression: do { myPrintf "test %d" (23 :: Int) }
In an equation for `main':
    main = do { myPrintf "test %d" (23 :: Int) }

GHC infers myPrintf :: String -> IO (), so there is obviously something wrong. I found something about Polyvariadic composition, but I'm not able to apply this to my problem. I'm not even sure if it would solve my problem.

The code is also available via gist.

like image 303
lewurm Avatar asked Nov 13 '22 23:11

lewurm


1 Answers

you can define your function by using hPrintf and the stdout handle.

Like that, the result of the function myPrintf remain an instance of the class HPrintfType

myPrintf::  (HPrintfType c) => String -> c
myPrintf = (hPrintf stdout) . (printf "log:%s")

main = myPrintf "test %d" (23 :: Int)

The polyvariadic form for the printf function works only because you have this instance definition :

(PrintfArg a, PrintfType r) => PrintfType (a -> r).

at each new PrintfArg parameter, type inference return an PrintfType class type if possible.

For working your logger function would have the following type :

logger :: (PrintfType c) => String -> c

but the compilator wil fail because the function return an IO () and not the more generic typeclass PrintfType.

In my opinion, only a modification of the module Text.Printf could help you because you can't create new instance of PrintfType as some method are hidden

like image 166
fp4me Avatar answered Dec 30 '22 19:12

fp4me