@hackage exon0.3.0.0

Monoidal Quasiquote Interpolation

This Haskell library provides quasiquote string interpolation with customizable concatenation for arbitrary types. Visit hackage to read the full API documentation.

The default case uses Monoid and IsString:

import Exon (exon)
import Data.Text (toUpper)

newtype Name =
  Name Text
  deriving newtype (Show, Monoid, IsString)

instance Semigroup Name where
  Name l <> Name r = Name (l <> " | " <> r)

lastName :: Name
lastName = "Fry"

up :: Name -> Name
up (Name name) = Name (toUpper name)

>>> [exon|Philip J. #{up lastName}|]
Name "Philip | J. | FRY"

Individual segments are tokenized at whitespace boundaries, expressions between #{ and } are inserted verbatim.

The default implementation ignores whitespace when concatenating, while it is preserved for String, Text etc.

An instance for String -> String is provided, used by showsPrec for example:


data Record =
  Record {
    number :: Int,
    maybeNumber :: Maybe Int,
    value :: Value
  }

instance Show Record where
  showsPrec d Record {..} =
    showParen (d > 10) $
      [exon|Record #{showsPrec 11 number} #{showsPrec 11 maybeNumber} #{showsPrec 11 value}|]

Customization

Concatenation is performed by the class Exon.Exon:

class Exon (tag :: Type) (a :: Type) where
  convertSegment :: Segment a -> Result a

  appendSegment :: Result a -> Segment a -> Result a

  insertWhitespace :: Result a -> String -> Segment a -> Result a

  concatSegments :: NonEmpty (Segment a) -> a

All methods have default implementations. The tag parameter is an arbitrary type that allows the creation of different quoters, with exon using the tag ExonDefault.

In order to get the default quoter to support custom rules for a type, one simply has to write an instance:

import Exon (Exon (..), ExonDefault, Result (..))
import qualified Exon as Segment (Segment(..))

instance Exon ExonDefault Name where
  convertSegment = \case
    Segment.String s -> Result (Name s)
    Segment.Expression name -> Result name
    Segment.Whitespace ws -> Result (Name " >>> ")

Acknowledgments

Inspired by the magnificent string-interpolate.