diff --git a/category-printf.cabal b/category-printf.cabal
--- a/category-printf.cabal
+++ b/category-printf.cabal
@@ -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
diff --git a/src/Control/Category/Printf.hs b/src/Control/Category/Printf.hs
--- a/src/Control/Category/Printf.hs
+++ b/src/Control/Category/Printf.hs
@@ -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))
-
diff --git a/src/Control/Category/Printf/ByteString/Lazy.hs b/src/Control/Category/Printf/ByteString/Lazy.hs
--- a/src/Control/Category/Printf/ByteString/Lazy.hs
+++ b/src/Control/Category/Printf/ByteString/Lazy.hs
@@ -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)
diff --git a/src/Control/Category/Printf/ByteString/Strict.hs b/src/Control/Category/Printf/ByteString/Strict.hs
--- a/src/Control/Category/Printf/ByteString/Strict.hs
+++ b/src/Control/Category/Printf/ByteString/Strict.hs
@@ -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
diff --git a/src/Control/Category/Printf/String.hs b/src/Control/Category/Printf/String.hs
--- a/src/Control/Category/Printf/String.hs
+++ b/src/Control/Category/Printf/String.hs
@@ -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)
diff --git a/src/Control/Category/Printf/Text/Lazy.hs b/src/Control/Category/Printf/Text/Lazy.hs
--- a/src/Control/Category/Printf/Text/Lazy.hs
+++ b/src/Control/Category/Printf/Text/Lazy.hs
@@ -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)
diff --git a/src/Control/Category/Printf/Text/Strict.hs b/src/Control/Category/Printf/Text/Strict.hs
--- a/src/Control/Category/Printf/Text/Strict.hs
+++ b/src/Control/Category/Printf/Text/Strict.hs
@@ -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
