format-heavy: Full-weight string formatting library, analog of Python's string.format

[ bsd3, library, text ] [ Propose Tags ] [ Report a vulnerability ]

This package contains full-featured string formatting function, similar to Python's string.format. Features include: * Automatically numbered variable placeholders; * Positional variable placeholders; * Named variable placeholders; * Placeholders can be used in any order; one variable can be used several times or not used at all.

  • Specific format can be used for each variable substitution. This package prefers functionality over "light weight" and (probably) performance. It also exposes all required interfaces to extend and customize it. See the README and examples/ directory for details.


[Skip to Readme]

Downloads

Maintainer's Corner

Package maintainers

For package maintainers and hackage trustees

Candidates

Versions [RSS] 0.1.0.2
Change log ChangeLog.md
Dependencies base (>=4.16 && <5), bytestring (>=0.12 && <0.13), containers (>=0.7 && <0.8), data-default (>=0.8 && <0.9), labels (>=0.3 && <0.4), parsec (>=3.1.18 && <3.2), template-haskell (>=2.18 && <2.24), text (>=2.1 && <3), th-lift (>=0.8 && <0.9), th-lift-instances (>=0.1 && <0.2), time (>=1.12 && <1.15) [details]
Tested with ghc ==9.2.8, ghc ==9.4.8, ghc ==9.6.7, ghc ==9.8.4, ghc ==9.10.3
License BSD-3-Clause
Author Ilya Portnov
Maintainer Leonid Bobylev <l3o6@proton.me>
Uploaded by l3o6 at 2026-09-11T16:04:15Z
Category Text
Home page https://github.com/lbobylev/format-heavy#format-heavy
Bug tracker https://github.com/lbobylev/format-heavy/issues
Source repo head: git clone https://github.com/lbobylev/format-heavy
Distributions
Reverse Dependencies 1 direct, 0 indirect [details]
Downloads 3 total (3 in the last 30 days)
Rating (no votes yet) [estimated by Bayesian average]
Your Rating
  • λ
  • λ
  • λ
Status Docs available [build log]
Last success reported on 2026-09-11 [all 1 reports]

Readme for format-heavy-0.1.0.2

[back to package description]

format-heavy

format-heavy is a continuation of text-format-heavy, originally created by Ilya Portnov, and provides Haskell string formatting inspired by Python's str.format() syntax.

It supports positional and named placeholders, per-value format specs, custom variable containers, and custom Formatable instances.

Quick Start

{-# LANGUAGE OverloadedStrings #-}

import Data.Text.Format.Heavy
import qualified Data.Text.Lazy as TL

hello :: TL.Text
hello = format "Hello, {name}!" [("name", "world" :: TL.Text)]

Placeholder Syntax

format "{}" (Single ("hello" :: TL.Text))
-- "hello"

format "{0} {1}" ("hello" :: TL.Text, "world" :: TL.Text)
-- "hello world"

format "{name}" [("name", "world" :: TL.Text)]
-- "world"

format "{{name}}" ()
-- "{name}"

The default syntax uses braces. Literal braces can be escaped as {{ and }}.

Passing Variables

Use Single for one value:

format "value: {}" (Single (42 :: Int))
-- "value: 42"

Use tuples or lists for positional placeholders:

format "{0}, {1}" ("hello" :: TL.Text, "world" :: TL.Text)
-- "hello, world"

format "{0}, {2}" (Several ["zero", "one", "two" :: TL.Text])
-- "zero, two"

Use association lists or maps for named placeholders:

format "Hello, {name}!" [("name", "Alice" :: TL.Text)]
-- "Hello, Alice!"

For heterogeneous named values, wrap each value in Variable:

let vars =
      [ ("name", Variable ("Alice" :: TL.Text))
      , ("count", Variable (3 :: Int))
      ]

format "{name} has {count} messages" vars
-- "Alice has 3 messages"

Format Specs

Format specs are written after : and interpreted by the value being formatted:

format "hex: {:#x}" (Single (427 :: Int))
-- "hex: 0x1ab"

format "float: {:+6.4}" (Single (2.718281828 :: Double))
-- "float: +2.7183"

format "center: <{:^10}>" (Single ("hello" :: String))
-- "center: <   hello  >"

format "upper: {:~u}" (Single ("hello" :: TL.Text))
-- "upper: HELLO"

format "bool: {:yes:no}" (Single False)
-- "bool: no"

Maybe values can specify a fallback after |:

format "value: {:.3|<missing>}" (Single (Nothing :: Maybe Float))
-- "value: <missing>"

Any value with a Show instance can be formatted through Shown:

format "debug: {}" (Single (Shown (Just True)))
-- "debug: Just True"

Error Handling

format is convenient and throws an error if formatting fails.

Use formatEither when errors should be handled explicitly:

import Data.Text.Format.Heavy.Build (formatEither)

formatEither "missing: {1}" (Single ("value" :: TL.Text))
-- Left "Parameter not found: 1"

Parsing And Introspection

Use Data.Text.Format.Heavy.Parse.parse to inspect a format string without formatting it:

import qualified Data.Text.Format.Heavy.Parse as Format

Format.parse "{name}"
-- Right [FormatReplacementField "name" Nothing]

Format.parse "{name:.2}"
-- Right [FormatReplacementField "name" (Just ".2")]

Format.parse "{{name}} {name}"
-- Right [FormatString "{name} ", FormatReplacementField "name" Nothing]

Format.parse "{value:{width}}"
-- Right [FormatReplacementField "value" (Just "{width}")]

This API exposes the field name and the raw format spec parsed from the default braces syntax. It does not format values.

Shell-Like Syntax

The default syntax uses braces. A shell-like syntax is also available:

import Data.Text.Format.Heavy
import Data.Text.Format.Heavy.Parse.Shell
import qualified Data.Text.Lazy as TL

format (parseShellFormat' "Hello, $name!") [("name", "world" :: TL.Text)]
-- "Hello, world!"

Braced shell-style placeholders can also carry format specs:

format (parseShellFormat' "hex: ${:#x}") (Single (427 :: Int))
-- "hex: 0x1ab"

Extending

Applications can extend the library by defining:

  • Formatable instances for custom value types.
  • VarContainer instances for custom variable sources.
  • Custom parsers that produce Format.

License

BSD-3-Clause. See LICENSE.