A type-safe text formatting library based on combinators.
Call with a formatting function like:
format- Format to a lazyTextvalue.sformat- Format to a strictTextvalue.bprint- Format to aBuildervalue.fprint- Format to stdout.hprint- Format to aHandle.
Call syntax:
format <format combinators> <param1> <param2>
Example:
format ("Person's name is " % text % ", age is " % hex) "Dave" 54or with short-names:
format ("Person's name is " % t % ", age is " % x) "Dave" 54Similar to C's printf:
printf("Person's name is %s, age is %x","Dave",54);and Common Lisp's FORMAT:
(format nil "Person's name is ~a, age is ~x" "Dave" 54)> format (text % "!") "Hi!"
"Hi!!"
> format (string % "!") "Hi!"
"Hi!!"> format int 23
"23"> format (fixed 0) 23.3
"23"
> format (fixed 2) 23.3333
"23.33"
> format shortest 23.3333
"23.3333"
> format shortest 0.0
"0"
> format sci 2.3
"2.3"
> format (scifmt Fixed (Just 0)) 2.3
"2"> format commas 123456778
"123,456,778"
> format commas 1234
"1,234"> format ords 1
"1st"
> format ords 2
"2nd"
> format ords 3
"3rd"
> format ords 4
"4th"> format hex 15
"f"
> format hex 25
"19"> now <- getCurrentTime
> later <- getCurrentTime
> format (dayOfMonth % "/" % month % "/" % year) now now now
"16/06/2014"
> format day now
"167"
> format hms now
"08:24:41"
> format tz now
"+0000"
> format datetime now
"Mon Jun 16 08:24:41 UTC 2014"
> format century now
"20"
> format (dayOfMonthOrd % " of " % monthName) now now
"16th of June"> format (diff False) (diffUTCTime later now)
"2 seconds"
> format (diff True) (diffUTCTime later now)
"in 2 seconds"
> format (diff True) (diffUTCTime now later)
"2 seconds ago"
> format (seconds 0 % " secs") (diffUTCTime now later)
"2 secs"> let Just old = parseTime defaultTimeLocale "%Y" "1980" :: Maybe UTCTime
> format (years 0) (diffUTCTime now old)
"34"
> format (diff True) (diffUTCTime now old)
"in 35 years"
> format (diff True) (diffUTCTime old now)
"35 years ago"
> format (days 0) (diffUTCTime old now)
"12585"
> format (days 0 % " days") (diffUTCTime old now)
"12585 days"> format (bytesMetric (fixed 1)) 4096
"4.1kB"
> format (bytesMetric shortest) 4096
"4.096kB"
> format (bytesMetric (fixed 2 % " ")) (1024*1024*5)
"5.24 MB"
> format (bytesBinary (fixed 1)) 4096
"4.0KiB"
> format (bytesBinary shortest) 4096
"4KiB"
> format (bytesBinary (fixed 2 % " ")) (1024*1024*5)
"5.00 MiB"%. is like % but feeds one formatter into another:
λ> format (left 2 '0' %. hex) 10
"0a"λ> now <- getCurrentTime
λ> format (year % "/" <> month <> "/" % dayOfMonth) now
"2015/01/27"You can include things verbatim in the formatter:
> format (now "This is printed now.")
"This is printed now."Although with OverloadedStrings you can just use string literals:
> format "This is printed now."
"This is printed now."You can handle things later which makes the formatter accept arguments:
> format (later (const "This is printed later.")) ()
"This is printed later."The type of the function passed to later should return an instance
of Monoid.
later :: (a -> Builder) -> Format r (a -> r)The function you format with (format, bprint, etc.)
will determine the monoid of choice. In the case of this library, the
top-level formating functions expect you to build a text Builder:
format :: Format Text a -> aBecause builders are efficient generators.
So in this case we will be expected to produce Builders from arguments:
format . later :: (a -> Builder) -> a -> TextTo do that for common types you can just re-use the formatting library and use bprint:
λ> :t bprint
bprint :: Format Builder a -> a
> :t bprint int 23
bprint int 23 :: BuilderComing back to later, we can now use it to build our own printer
combinators:
> let mint = later (maybe "" (bprint int))
> :t mint
mint :: Integral a => Format r (Maybe a -> r)Now mint is a formatter to show Maybe Integer:
> format mint (readMaybe "23")
"23"
> format mint (readMaybe "foo")
""Although a better, more general combinator might be:
> let mfmt x f = later (maybe x (bprint f))Now you can use it to maybe format things:
> format (mfmt "Nope!" int) (readMaybe "foo")
"Nope!"If you're using a type which provides its own builder, like the
Scientific type:
import Data.Text.Lazy.Builder.Scientific
scientificBuilder :: Scientific -> Builder
formatScientificBuilder :: FPFormat -> Maybe Int -> Scientific -> BuilderThen you can use later easily:
> format (later scientificBuilder) 23.4
"23.4"Actually, there are now already two handy combinators (sci and
scifmt) for the Scientific type as shown above in the Decimals
section.
