MIT licensed and maintained by Travis Cardwell
This version can be pinned in stack with:ttc-1.5.0.0@sha256:f1bd7cd851d53c309d65485517c2c3c90b0d569b0b1f18b9682fee46ca14ef0f,1884

Module documentation for 1.5.0.0

Used by 2 packages in nightly-2025-02-05(full list with versions):

TTC: Textual Type Classes

Project Status: Active – The project has reached a stable, usable state and is being actively developed. GitHub CI Hackage Stackage LTS Stackage Nightly

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:

Textual

The Textual type class is used to convert between the following textual data types:

  • String
  • Strict Text
  • Lazy Text
  • Text Builder
  • ShortText
  • Strict ByteString
  • Lazy ByteString
  • ByteString Builder (and Data.Binary.Builder)
  • ShortByteString

This type class has two key features:

  • Type conversion is not done through a fixed type (such as String or Text).
  • 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 Unreleased is 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:
    1. Breaking
    2. 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 RenderDefault Bool instance
  • Add ParseDefault Bool instance
  • Add missing RenderDefault and ParseDefault instances for TLB.Builder, ST.ShortText, BSB.Builder, and SBS.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.Wrapper module
  • Add Template Haskell functions for loading default instances
  • Bump base dependency version upper bound
  • Bump template-haskell dependency version upper bound

1.4.0.0 (2023-12-03)

Breaking

  • Add support for ShortText

Non-Breaking

  • Bump base dependency version upper bound
  • Bump template-haskell dependency version upper bound

1.3.0.0 (2023-09-17)

Breaking

  • Add typed Template Haskell expression IsString orphan instance
  • Add parseOrFail functions

Non-Breaking

  • Bump bytestring dependency version upper bound
  • Bump tasty dependency version upper bound
  • Bump text dependency version upper bound

1.2.1.0 (2023-03-21)

Non-Breaking

  • Bump template-haskell dependency version upper bound
  • Adjust dependency constraints to match tested versions

1.2.0.0 (2022-03-18)

Breaking

  • Add withError functions
  • Add prefixError functions

1.1.1.1 (2022-03-01)

Non-Breaking

  • Refactor Makefile

1.1.1.0 (2021-12-25)

Non-Breaking

  • Bump text dependency version upper bound

1.1.0.2 (2021-08-23)

Non-Breaking

  • Bump template-haskell dependency version upper bound
  • Add CPP macro around BSB.Builder Show instance in test code

1.1.0.1 (2021-06-25)

Non-Breaking

  • Refactor Nix configuration

1.1.0.0 (2021-06-10)

Breaking

  • Add Textual TLB.Builder instance and related functions
  • Add Textual BSB.Builder instance and related functions
  • Add Textual SBS.ShortByteString instance and related functions
  • Add RenderDefault and ParseDefault type classes and instances
  • Remove Data.TTC.Instances

Non-Breaking

  • Add HasCallStack to 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, and renderSBS functions
  • Use Textual error messages for parseEnum'

Non-Breaking

  • Add @since annotations
  • 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 Textual error messages
  • Add maybeParseWithRead function

0.2.3.0 (2020-09-25)

Non-Breaking

  • Bump bytestring dependency version upper bound

0.2.2.0 (2020-05-17)

Non-Breaking

  • Bump template-haskell dependency version upper bound
    • Update lift example for compatibility with template-haskell 2.16.0.0

0.2.1.0 (2020-05-11)

Non-Breaking

  • Update examples to support older libraries
  • Refactor Makefile, add STACK_NIX_PATH support
  • Add test-all command to Makefile
  • Bump tasty dependency 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 time dependency 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