packages feed

category-printf 0.1.0.2 → 0.1.1.0

raw patch · 7 files changed

+242/−41 lines, 7 filesPVP: major bump suggested

API removals or changes: PVP suggests a major version bump

API changes (from Hackage documentation)

- Control.Category.Printf: instance (a ~ b, Data.String.IsString s, GHC.Base.Monoid s) => Data.String.IsString (Control.Comonad.Cokleisli ((->) s) a b)
+ Control.Category.Printf: bind :: (t -> Format s a b) -> Format s a (t -> b)
+ Control.Category.Printf: instance (a ~ b, IsString s, Monoid s) => IsString (Cokleisli ((->) s) a b)
+ Control.Category.Printf: mapMonoid :: (m -> m') -> Format m a b -> Format m' a b
+ Control.Category.Printf: signedWith :: (Num t, Ord t, Monoid s) => (s -> s) -> (s -> s) -> Format s a (t -> b) -> Format s a (t -> b)
+ Control.Category.Printf.ByteString.Lazy: padLeft :: ByteString -> Int64 -> Format ByteString a b -> Format ByteString a b
+ Control.Category.Printf.ByteString.Lazy: padRight :: ByteString -> Int64 -> Format ByteString a b -> Format ByteString a b
+ Control.Category.Printf.ByteString.Strict: padLeft :: ByteString -> Int -> Format ByteString a b -> Format ByteString a b
+ Control.Category.Printf.ByteString.Strict: padRight :: ByteString -> Int -> Format ByteString a b -> Format ByteString a b
+ Control.Category.Printf.String: padLeft :: String -> Int -> Format String a b -> Format String a b
+ Control.Category.Printf.String: padRight :: String -> Int -> Format String a b -> Format String a b
+ Control.Category.Printf.Text.Lazy: padLeft :: Text -> Int64 -> Format Text a b -> Format Text a b
+ Control.Category.Printf.Text.Lazy: padRight :: Text -> Int64 -> Format Text a b -> Format Text a b
+ Control.Category.Printf.Text.Strict: padLeft :: Text -> Int -> Format Text a b -> Format Text a b
+ Control.Category.Printf.Text.Strict: padRight :: Text -> Int -> Format Text a b -> Format Text a b

Files

category-printf.cabal view
@@ -1,5 +1,5 @@ name:                category-printf-version:             0.1.0.2+version:             0.1.1.0 synopsis:            Highbrow approach to type-safe printf format specifications. description:         We use the co-Kleisli category for the comonad of                      functions out of a fixed monoid to implement a generic
src/Control/Category/Printf.hs view
@@ -1,33 +1,41 @@-{-# LANGUAGE OverloadedStrings, FlexibleInstances, TypeFamilies #-}+{-# LANGUAGE OverloadedStrings, FlexibleInstances, TypeFamilies, RankNTypes #-}  module Control.Category.Printf -       ( module Control.Category-       -- * Basics-       , Format-       , printfWith-       , sprintf-       , c-       , i-       , spliceWith-       , s-       , generalizeString-       -- * Numeric formatting-       , intAtBase-       , hex-       , oct-       , eFloat-       , fFloat-       , gFloat-       -- * Argument stack manipulation-       , push-       , dup-       , swap-       , skip-       , apply-       , apply2-       ) where+  ( +  -- | Note that you'll probably want to import both this module and one of the other string-type specific modules depending on+  -- which sort of strings you'll be working with. You'll also probably want to turn on the OverloadedStrings extension so as to+  -- be able to use string literals as formatters which insert themselves.+    module Control.Category+  -- * Basics+  , Format+  , printfWith+  , sprintf+  , c+  , i+  , spliceWith+  , s+  , bind+  , mapMonoid+  , generalizeString+  -- * Numeric formatting+  , signedWith+  , intAtBase+  , hex+  , oct+  , eFloat+  , fFloat+  , gFloat+  -- * Argument stack manipulation+  , push+  , dup+  , swap+  , skip+  , apply+  , apply2+  ) where -import Prelude hiding (id, (.))+import Prelude hiding (id, (.), length)+import Data.List (genericLength, genericReplicate) import Control.Arrow import Control.Category import Data.Monoid@@ -36,6 +44,11 @@  import Data.String +import qualified Data.Text as T+import qualified Data.Text.Lazy as TL+import qualified Data.ByteString as B+import qualified Data.ByteString.Lazy as BL+ -- | Handy type synonym for the things we're working with. -- You should regard a value of type @Format m a b@ as something which explains how to write -- some element of the monoid @m@ (a "string" for our purposes), and which will change the type@@ -56,11 +69,20 @@ instance (a ~ b, IsString s, Monoid s) => IsString (Cokleisli ((->) s) a b) where   fromString = c . fromString --- | Formatter for a constant string.+-- | Formatter for a constant string. Note that for string literals, this is implicit if you turn on+-- the OverloadedStrings extension.+--+-- >>> let x = "world" in printfLn (c "Hello, " . c x . c "!")+-- Hello, world! c :: (Monoid m) => m -> Format m a a c x = Cokleisli ($ x)  -- | Inclusion of a string as an argument.+-- +-- >>> mapM_ (printfLn ("Hello, " . i . "!")) ["Anne", "Bob", "world"]+-- Hello, Anne!+-- Hello, Bob!+-- Hello, world! i :: Format m a (m -> a) i = Cokleisli id @@ -70,10 +92,29 @@ spliceWith f = Cokleisli (. f)  -- | Splice in anything showable.+-- +-- >>> printfLn ("list: " . s . "  tuple: " . s . "  string: " . s) [1,2,3] ("hello", 'a') "there"+-- list: [1,2,3]  tuple: ("hello",'a')  string: "there" s :: (Monoid s, IsString s, Show t) => Format s a (t -> a) s = spliceWith (fromString . show) --- | Transform a formatter for one type of string to another using the given function.+-- | Select which formatter to apply based on an argument.+--+-- >>> printfLn (bind (\b -> if b then eFloat Nothing else fFloat Nothing)) False 5328+-- 5328.0+--+-- >>> printfLn (bind (\b -> if b then eFloat Nothing else fFloat Nothing)) True 5328+-- 5.328e3+--+-- >>> printfLn (bind (\f -> f Nothing)) eFloat 5328+-- 5.328e3+bind :: (t -> Format s a b) -> Format s a (t -> b)+bind h = Cokleisli (\k x -> runCokleisli (h x) k)++-- | Apply a function to the output of a formatter, possibly changing its type.+-- +-- >>> printfLn (mapMonoid (map toUpper) hex) 0xcafe1234+-- CAFE1234 mapMonoid :: (m -> m') -> Format m a b -> Format m' a b mapMonoid u f = Cokleisli (\k -> runCokleisli f (k . u)) @@ -81,22 +122,36 @@ generalizeString :: (IsString s, Monoid s) => Format String a b -> Format s a b generalizeString = mapMonoid fromString +-- | Transform a numeric formatter which will be used to handle absolute values, applying the first given+-- function to the string to be spliced when the argument is negative, and the second given function otherwise.+--+-- >>> printfLn (signedWith (\v -> mconcat ["(",v,")"]) id (fFloat (Just 2))) (-pi)+-- (3.14)+--+-- >>> printfLn (signedWith ("-"<>) ("+"<>) (padLeft "0" 5 s)) (-439)+-- -00439+-- +-- >>> printfLn (signedWith ("-"<>) ("+"<>) (padLeft "0" 5 s)) 1278+-- +01278+signedWith :: (Num t, Ord t, Monoid s) => (s -> s) -> (s -> s) -> Format s a (t -> b) -> Format s a (t -> b)+signedWith neg nonneg x = dup . bind (\n -> if n < 0 then mapMonoid neg (apply abs . x) else mapMonoid nonneg x)+ -- | Show an integral value using the given base, and using the provided function to determine how -- to display individual digits. intAtBase :: (Real t, Integral t, Show t, Monoid s, IsString s)           => t -> (Int -> Char) -> Format s a (t -> a)-intAtBase b showDigit = generalizeString $-  spliceWith (\n -> showSigned (showIntAtBase b showDigit) 0 n "")+intAtBase b showDigit = generalizeString $ spliceWith (\n -> showSigned (showIntAtBase b showDigit) 0 n "")  -- | Show an integral value in hexadecimal.+--+-- >>> printfLn (dup . s . " in hexadecimal is " . hex) 51966+-- 51966 in hexadecimal is cafe hex :: (Integral t, Show t, Monoid s, IsString s) => Format s a (t -> a)-hex = generalizeString $-  spliceWith (\n -> showSigned showHex 0 n "")+hex = generalizeString $ spliceWith (\n -> showSigned showHex 0 n "")  -- | Show an integral value in octal. oct :: (Integral t, Show t, Monoid s, IsString s) => Format s a (t -> a)-oct = generalizeString $-  spliceWith (\n -> showSigned showOct 0 n "")+oct = generalizeString $ spliceWith (\n -> showSigned showOct 0 n "")  -- | Show a floating point value in exponential format. (e.g. 2.45e2, -1.5e-3) -- If `digs` is Nothing, the value is shown to full precision, if it is Just d then at most@@ -143,6 +198,10 @@ apply f = arr (\k x -> k (f x))  -- | Apply a binary function to the top two arguments on the stack.+--+-- >>> printfLn (dup . s . " plus " . swap . dup . s . " equals " . apply2 (+) . s) 4 6+-- 4 plus 6 equals 10+-- >>> printfLn (arr (\k x y -> k x y (x+y)) . s . " plus " . s . " equals " . s) 4 6+-- 4 plus 6 equals 10 apply2 :: Monoid m => (u -> v -> w) -> Format m (w -> a) (u -> v -> a) apply2 f = arr (\k x y -> k (f x y))-
src/Control/Category/Printf/ByteString/Lazy.hs view
@@ -4,14 +4,21 @@        , printfLn        , hPrintf        , hPrintfLn+       , padLeft+       , padRight        ) where  import Prelude hiding (id, (.))-import Control.Comonad+ import Control.Category.Printf+import Control.Comonad+import Data.Monoid+import Data.Int (Int64)+ import Data.ByteString.Lazy (ByteString) import qualified Data.ByteString.Lazy as B import qualified Data.ByteString.Lazy.Char8 as BC+ import System.IO (Handle)  printf :: Format ByteString (IO ()) b -> b@@ -26,3 +33,24 @@ hPrintfLn :: Handle -> Format ByteString (IO ()) b -> b hPrintfLn h = printfWith (BC.hPutStrLn h) +-- | padLeft s n f will transform the formatter f, ensuring that the output produced is at least length n+-- by appending sufficiently many copies of s on the left. The string s should have length at least 1,+-- otherwise this has no effect. In cases where s has length greater than 1, the last occurrence of s+-- will be truncated as necessary to fit the necessary width.+padLeft :: ByteString -> Int64 -> Format ByteString a b -> Format ByteString a b+padLeft s _ f | B.length s < 1 = f+padLeft s n f = (`mapMonoid` f) $ \x ->+  let k = B.length x+      d = n - k+  in B.take d (B.cycle s) <> x++-- | padRight s n f will transform the formatter f, ensuring that the output produced is at least length n+-- by appending sufficiently many copies of s on the right. The string s should have length at least 1,+-- otherwise this has no effect. In cases where s has length greater than 1, the last occurrence of s+-- will be truncated as necessary to fit the necessary width.+padRight :: ByteString -> Int64 -> Format ByteString a b -> Format ByteString a b+padRight s _ f | B.length s < 1 = f+padRight s n f = (`mapMonoid` f) $ \x ->+  let k = B.length x+      d = n - k+  in x <> B.take d (B.cycle s)
src/Control/Category/Printf/ByteString/Strict.hs view
@@ -4,14 +4,20 @@        , printfLn        , hPrintf        , hPrintfLn+       , padLeft+       , padRight        ) where  import Prelude hiding (id, (.))-import Control.Comonad+ import Control.Category.Printf+import Control.Comonad+import Data.Monoid+ import Data.ByteString (ByteString) import qualified Data.ByteString as B import qualified Data.ByteString.Char8 as BC+ import System.IO (Handle)  printf :: Format ByteString (IO ()) b -> b@@ -26,3 +32,26 @@ hPrintfLn :: Handle -> Format ByteString (IO ()) b -> b hPrintfLn h = printfWith (BC.hPutStrLn h) +-- | padLeft s n f will transform the formatter f, ensuring that the output produced is at least length n+-- by appending sufficiently many copies of s on the left. The string s should have length at least 1,+-- otherwise this has no effect. In cases where s has length greater than 1, the last occurrence of s+-- will be truncated as necessary to fit the necessary width.+padLeft :: ByteString -> Int -> Format ByteString a b -> Format ByteString a b+padLeft s _ f | B.length s < 1 = f+padLeft s n f = (`mapMonoid` f) $ \x ->+  let k = B.length x+      l = B.length s+      (q,r) = (n - k) `divMod` l+  in mconcat (replicate q s) <> B.take r s <> x++-- | padRight s n f will transform the formatter f, ensuring that the output produced is at least length n+-- by appending sufficiently many copies of s on the right. The string s should have length at least 1,+-- otherwise this has no effect. In cases where s has length greater than 1, the last occurrence of s+-- will be truncated as necessary to fit the necessary width.+padRight :: ByteString -> Int -> Format ByteString a b -> Format ByteString a b+padRight s _ f | B.length s < 1 = f+padRight s n f = (`mapMonoid` f) $ \x ->+  let k = B.length x+      l = B.length s+      (q,r) = (n - k) `divMod` l+  in x <> mconcat (replicate q s) <> B.take r s
src/Control/Category/Printf/String.hs view
@@ -4,6 +4,8 @@        , printfLn        , hPrintf        , hPrintfLn+       , padLeft+       , padRight        ) where  import Control.Comonad@@ -21,3 +23,25 @@  hPrintfLn :: Handle -> Format String (IO ()) b -> b hPrintfLn h = printfWith (hPutStrLn h)++-- | padLeft s n f will transform the formatter f, ensuring that the output produced is at least length n+-- by appending sufficiently many copies of s on the left. The string s should have length at least 1,+-- otherwise this has no effect. In cases where s has length greater than 1, the last occurrence of s+-- will be truncated as necessary to fit the necessary width.+padLeft :: String -> Int -> Format String a b -> Format String a b+padLeft s _ f | length s < 1 = f+padLeft s n f = (`mapMonoid` f) $ \x ->+  let k = length x+      d = n - k+  in take d (cycle s) ++ x++-- | padRight s n f will transform the formatter f, ensuring that the output produced is at least length n+-- by appending sufficiently many copies of s on the right. The string s should have length at least 1,+-- otherwise this has no effect. In cases where s has length greater than 1, the last occurrence of s+-- will be truncated as necessary to fit the necessary width.+padRight :: String -> Int -> Format String a b -> Format String a b+padRight s _ f | length s < 1 = f+padRight s n f = (`mapMonoid` f) $ \x ->+  let k = length x+      d = n - k+  in x ++ take d (cycle s)
src/Control/Category/Printf/Text/Lazy.hs view
@@ -4,13 +4,21 @@        , printfLn        , hPrintf        , hPrintfLn+       , padLeft+       , padRight        ) where  import Prelude hiding (id, (.))-import Control.Comonad+ import Control.Category.Printf+import Control.Comonad+import Data.Monoid+import Data.Int (Int64)+ import Data.Text.Lazy (Text)+import qualified Data.Text.Lazy as T import qualified Data.Text.Lazy.IO as T+ import System.IO (Handle)  printf :: Format Text (IO ()) b -> b@@ -24,3 +32,25 @@  hPrintfLn :: Handle -> Format Text (IO ()) b -> b hPrintfLn h = printfWith (T.hPutStrLn h)++-- | padLeft s n f will transform the formatter f, ensuring that the output produced is at least length n+-- by appending sufficiently many copies of s on the left. The string s should have length at least 1,+-- otherwise this has no effect. In cases where s has length greater than 1, the last occurrence of s+-- will be truncated as necessary to fit the necessary width.+padLeft :: Text -> Int64 -> Format Text a b -> Format Text a b+padLeft s _ f | T.length s < 1 = f+padLeft s n f = (`mapMonoid` f) $ \x ->+  let k = T.length x+      d = n - k+  in T.take d (T.cycle s) <> x++-- | padRight s n f will transform the formatter f, ensuring that the output produced is at least length n+-- by appending sufficiently many copies of s on the right. The string s should have length at least 1,+-- otherwise this has no effect. In cases where s has length greater than 1, the last occurrence of s+-- will be truncated as necessary to fit the necessary width.+padRight :: Text -> Int64 -> Format Text a b -> Format Text a b+padRight s _ f | T.length s < 1 = f+padRight s n f = (`mapMonoid` f) $ \x ->+  let k = T.length x+      d = n - k+  in x <> T.take d (T.cycle s)
src/Control/Category/Printf/Text/Strict.hs view
@@ -4,13 +4,20 @@        , printfLn        , hPrintf        , hPrintfLn+       , padLeft+       , padRight        ) where  import Prelude hiding (id, (.))-import Control.Comonad+ import Control.Category.Printf+import Control.Comonad+import Data.Monoid+ import Data.Text (Text)+import qualified Data.Text as T import qualified Data.Text.IO as T+ import System.IO (Handle)  printf :: Format Text (IO ()) b -> b@@ -24,3 +31,27 @@  hPrintfLn :: Handle -> Format Text (IO ()) b -> b hPrintfLn h = printfWith (T.hPutStrLn h)++-- | padLeft s n f will transform the formatter f, ensuring that the output produced is at least length n+-- by appending sufficiently many copies of s on the left. The string s should have length at least 1,+-- otherwise this has no effect. In cases where s has length greater than 1, the last occurrence of s+-- will be truncated as necessary to fit the necessary width.+padLeft :: Text -> Int -> Format Text a b -> Format Text a b+padLeft s _ f | T.length s < 1 = f+padLeft s n f = (`mapMonoid` f) $ \x ->+  let k = T.length x+      l = T.length s+      (q,r) = (n - k) `divMod` l+  in mconcat (replicate q s) <> T.take r s <> x++-- | padRight s n f will transform the formatter f, ensuring that the output produced is at least length n+-- by appending sufficiently many copies of s on the right. The string s should have length at least 1,+-- otherwise this has no effect. In cases where s has length greater than 1, the last occurrence of s+-- will be truncated as necessary to fit the necessary width.+padRight :: Text -> Int -> Format Text a b -> Format Text a b+padRight s _ f | T.length s < 1 = f+padRight s n f = (`mapMonoid` f) $ \x ->+  let k = T.length x+      l = T.length s+      (q,r) = (n - k) `divMod` l+  in x <> mconcat (replicate q s) <> T.take r s