[ create a new paste ] login | about

Link: http://codepad.org/xY2quxH0    [ raw code | output | fork | 1 comment ]

Haskell, pasted on Jul 8:
-- Haskell98!

-- Generic polyvariadic printf
-- It can handle an arbitrary number of Showable arguments

module Main where

-- Needed only for the sake of Haskell98
-- If we are OK with flexible instances, this newtype can be disposed of
newtype RString = RString{unR:: String} 

class SPrintF r where
    pr_aux :: [FDesc] -> [String] -> r

-- These two instances are all we ever need

instance SPrintF RString where
    pr_aux desc acc = RString . concat . reverse $ foldl f acc desc
     where
     f acc (FD_lit s) = s : acc
     f acc FD_str     = error "Unfulfilled %s formatter"

instance (Show a, SPrintF r) => SPrintF (a->r) where
    pr_aux desc acc x = pr_aux desc' acc'
     where
     (desc',acc') = fmtx desc acc
     fmtx [] acc     = error "No formatting directive for the argument"
     fmtx (FD_lit s:desc) acc = fmtx desc (s:acc)
     fmtx (FD_str : desc) acc = (desc, unq (show x) : acc)
     unq ('"' : str) | last str == '"' = init str
     unq str  = str


printf str = pr_aux (convert_to_fdesc str) []

-- tests

t1 = unR $ printf "Hi there"
-- "Hi there"

t2 = unR $ printf "Hi %s!" "there"
-- "Hi there!"

t3 = unR $ printf "The value of %s is %s" "x" 3
-- "The value of x is 3"

t4 = unR $ printf "The value of %s is %s" "x" [5]
-- "The value of x is [5]"



-- A very simple language of format descriptors

data FDesc = FD_lit String | FD_str deriving (Eq, Show)

-- Convert "insert %s here" into 
-- [FD_lit "insert ", FD_str, FD_lit " here"]
convert_to_fdesc :: String -> [FDesc]
convert_to_fdesc str = 
    case break (=='%') str of
      (s1,"") -> make_lit s1
      (s1,'%':'s':rest) -> make_lit s1 ++ FD_str : convert_to_fdesc rest
      (_,s2) -> error $ "bad descriptor: " ++ take 5 s2
 where
 make_lit "" = []
 make_lit str = [FD_lit str]

test_cvf = and [
    convert_to_fdesc "Simple lit" ==
       [FD_lit "Simple lit"],
    convert_to_fdesc "%s insert" ==
       [FD_str,FD_lit " insert"],
    convert_to_fdesc "insert %s here" ==
    [FD_lit "insert ",FD_str,FD_lit " here"]
    ]

main = putStrLn $ unR $ printf "%s %s %s %s %s %s %s %s %s %s" 1 2 3 4 5 6 7 8 9 10


Output:
1
1 2 3 4 5 6 7 8 9 10


Create a new paste based on this one


Comments:
posted by keigoi on Jul 8
reply