ttc
Textual Type Classes
https://github.com/ExtremaIS/ttc-haskell/tree/main/ttc#readme
| LTS Haskell 24.16: | 1.5.0.0 |
| Stackage Nightly 2025-10-24: | 1.5.0.0 |
| Latest on Hackage: | 1.5.0.0 |
ttc-1.5.0.0@sha256:f1bd7cd851d53c309d65485517c2c3c90b0d569b0b1f18b9682fee46ca14ef0f,1884Module documentation for 1.5.0.0
TTC: Textual Type Classes
Overview
TTC, an initialism of Textual Type Classes, is a library that provides
Render and Parse type classes for conversion between data types and
textual data types (strings). Use the Show and Read type classes for
debugging/development, and use the Render and Parse type classes for your
own purposes. The library also provides various ways to validate constants at
compile-time.
This package (ttc) uses a Textual type class for conversion between
textual data types. This package uses simple types and compiles quickly, but
the supported textual data types are fixed. It is not possible for users to
add support for additional textual data types.
Since a type may have at most one instance of a given type class, special care must be taken when defining type class instances in a shared library. In particular, orphan instances should generally not be used in shared libraries since they prevent users of the libraries from writing their own instances.
Render and Parse are best used with types that have canonical textual
representations, such as textual identifiers. When there is more than one way
to create a textual representation, such as configurable formatting, using a
normal function is probably more appropriate. Such a function can make use of
the Textual type class to support multiple textual data types.
This overview includes a brief introduction of the library. The following resources are also available:
- API documentation is viewable on Hackage.
- A series of articles gives a guided tour of the library.
- The
ttc-examplesdirectory in the repository contains usage examples.
Textual
The Textual type class is used to convert between the following textual data
types:
String- Strict
Text - Lazy
Text TextBuilderShortText- Strict
ByteString - Lazy
ByteString ByteStringBuilder(andData.Binary.Builder)ShortByteString
This type class has two key features:
- Type conversion is not done through a fixed type (such as
StringorText). - It has a single type variable, making it easy to write functions that accept arguments and/or return values that may be any of the supported textual data types.
For more details, see the Textual Type Class article.
Render
The Render type class renders a data type as a Textual data type:
class Render a where
render :: Textual t => a -> t
It is analogous to the Show type class, which can be reserved for
debugging/development.
The render function returns any of the supported textual data types. Use
the textual data type that is most natural in the implementation of render
instances, and return values are converted to other textual data types when
necessary. The Show and IsString type classes are not used, so use of the
String type is not required.
As a simple example, consider a Username type that is implemented as a
newtype over Text:
module Username (Username) where
import Control.Monad (unless, when)
import Data.Char (isAsciiLower)
import qualified Data.Text as T
import Data.Text (Text)
import qualified Data.TTC as TTC
newtype Username = Username Text
deriving (Eq, Ord, Show)
instance TTC.Render Username where
render (Username t) = TTC.convert t
If a username needs to be included in a String error message, conversion is
automatic:
putStrLn $ "user not found: " ++ TTC.render uname
For more details, see the Render and Parse article.
Parse
The Parse type class parses a data type from a Textual data type:
class Parse a where
parse :: (Textual t, Textual e) => t -> Either e a
It is analogous to the Read type class, which can be reserved for
debugging/development.
The parse function takes any of the supported textual data types as an
argument. Use the textual data type that is most natural in the
implementation of parse instances, and arguments are converted from other
textual data types when necessary. The IsString type class is not used, so
use of the String type is not required.
Here is an example instance for Username, implementing some restrictions:
instance TTC.Parse Username where
parse = TTC.asT $ \t -> TTC.prefixErrorS "invalid username: " $ do
unless (T.all isAsciiLower t) $ Left "not only lowercase ASCII letters"
let len = T.length t
when (len < 3) $ Left "fewer than 3 characters"
when (len > 12) $ Left "more than 12 characters"
pure $ Username t
If a username needs to be parsed from a String, conversion is automatic:
case TTC.parse s :: Either String Username of
Right uname -> "valid username: " ++ TTC.render uname
Left err -> err
For more details, see the Render and Parse article.
Constant Validation
TTC provides functions to validate constants at compile-time, using Template
Haskell. For example, a Username constant can be defined as follows:
user :: Username
user = $$(TTC.valid "tcard")
For more details, see the Validated Constants article.
Project
See the project README for general project information.
Changes
ttc Changelog
This project follows the Haskell package versioning policy, with
versions in A.B.C.D format. A may be incremented arbitrarily for
non-technical reasons, but semantic versioning is otherwise
followed, where A.B is the major version, C is the minor version, and D
is the patch version. Initial development uses versions 0.0.C.D, for which
every version is considered breaking.
The format of this changelog is based on Keep a Changelog, with the following conventions:
- Level-two heading
Unreleasedis used to track changes that have not been released. - Other level-two headings specify the release in
A.B.C.D (YYYY-MM-DD)format, with newer versions above older versions. - Level-three headings are used to categorize changes as follows:
- Breaking
- Non-Breaking
- Changes are listed in arbitrary order and present tense.
1.5.0.0 (2025-01-02)
Breaking
- Change type argument order for easier use with
TypeApplications - Add
RenderDefaultBoolinstance - Add
ParseDefaultBoolinstance - Add missing
RenderDefaultandParseDefaultinstances forTLB.Builder,ST.ShortText,BSB.Builder, andSBS.ShortByteString - Remove support for GHC 8.6, constraining lower bounds
- Remove support for GHC 8.4, constraining lower bounds
- Remove support for GHC 8.2, constraining lower bounds
- Change minimal Cabal from 1.24 to 3.0
Non-Breaking
- Add
Data.TTC.Wrappermodule - Add Template Haskell functions for loading default instances
- Bump
basedependency version upper bound - Bump
template-haskelldependency version upper bound
1.4.0.0 (2023-12-03)
Breaking
- Add support for
ShortText
Non-Breaking
- Bump
basedependency version upper bound - Bump
template-haskelldependency version upper bound
1.3.0.0 (2023-09-17)
Breaking
- Add typed Template Haskell expression
IsStringorphan instance - Add
parseOrFailfunctions
Non-Breaking
- Bump
bytestringdependency version upper bound - Bump
tastydependency version upper bound - Bump
textdependency version upper bound
1.2.1.0 (2023-03-21)
Non-Breaking
- Bump
template-haskelldependency version upper bound - Adjust dependency constraints to match tested versions
1.2.0.0 (2022-03-18)
Breaking
- Add
withErrorfunctions - Add
prefixErrorfunctions
1.1.1.1 (2022-03-01)
Non-Breaking
- Refactor
Makefile
1.1.1.0 (2021-12-25)
Non-Breaking
- Bump
textdependency version upper bound
1.1.0.2 (2021-08-23)
Non-Breaking
- Bump
template-haskelldependency version upper bound - Add CPP macro around
BSB.BuilderShowinstance in test code
1.1.0.1 (2021-06-25)
Non-Breaking
- Refactor Nix configuration
1.1.0.0 (2021-06-10)
Breaking
- Add
TextualTLB.Builderinstance and related functions - Add
TextualBSB.Builderinstance and related functions - Add
TextualSBS.ShortByteStringinstance and related functions - Add
RenderDefaultandParseDefaulttype classes and instances - Remove
Data.TTC.Instances
Non-Breaking
- Add
HasCallStackto unsafe functions
1.0.0.0 (2021-06-03)
Non-Breaking
- Add Cabal support to
Makefile
0.4.0.0 (2021-03-27)
Breaking
- Add support for GHC 9
- Add
renderTLB,renderBSB, andrenderSBSfunctions - Use
Textualerror messages forparseEnum'
Non-Breaking
- Add
@sinceannotations - Rename Git default branch to
main - Use GitHub Actions instead of Travis CI
- Add Cabal tests to GitHub Actions
- Add stan static analysis
0.3.0.0 (2020-11-03)
Breaking
- Use
Textualerror messages - Add
maybeParseWithReadfunction
0.2.3.0 (2020-09-25)
Non-Breaking
- Bump
bytestringdependency version upper bound
0.2.2.0 (2020-05-17)
Non-Breaking
- Bump
template-haskelldependency version upper bound- Update
liftexample for compatibility withtemplate-haskell 2.16.0.0
- Update
0.2.1.0 (2020-05-11)
Non-Breaking
- Update examples to support older libraries
- Refactor
Makefile, addSTACK_NIX_PATHsupport - Add
test-allcommand toMakefile - Bump
tastydependency version upper bound
0.2.0.0 (2019-12-15)
Non-Breaking
- Add untyped validation functions
- Move examples to a separate package
- Refactor examples and add more
0.1.0.1 (2019-12-02)
Non-Breaking
- Bump
timedependency version upper bound
0.1.0.0 (2019-12-01)
Non-Breaking
- Update Cabal file in preparation for release to Hackage
0.0.0.4 (2019-11-30)
Non-Breaking
- Update Cabal file in preparation for release to Hackage
- Update documentation
- Add examples
0.0.0.3 (2019-11-28)
Non-Breaking
- Add continuous integration support
0.0.0.2 (2019-11-28)
Non-Breaking
- Update Cabal metadata
- Update README
0.0.0.1 (2019-11-23)
Breaking
- Initial public release