exon: Monoidal Quasiquote Interpolation

This is a package candidate release! Here you can preview how this package release will appear once published to the main package index (which can be accomplished via the 'maintain' link below). Please note that once a package has been published to the main package index it cannot be undone! Please consult the package uploading documentation for more information.

[maintain] [Publish]

See https://hackage.haskell.org/package/exon/docs/Exon.html


[Skip to Readme]

Properties

Versions 0.1.0.0, 0.1.0.0, 0.1.1.0, 0.2.0.0, 0.2.0.1
Change log Changelog.md
Dependencies base (==4.*), flatparse (==0.2.*), haskell-src-exts (<1.24), haskell-src-meta (<0.9), relude (>=0.7 && <1.2), template-haskell, text [details]
License BSD-2-Clause-Patent
Copyright 2021 Torsten Schmits
Author Torsten Schmits
Maintainer haskell@tryp.io
Category String
Home page https://github.com/tek/exon#readme
Bug tracker https://github.com/tek/exon/issues
Source repo head: git clone https://github.com/tek/exon
Uploaded by tek at 2021-07-28T21:59:42Z

Modules

[Index]

Downloads

Maintainer's Corner

For package maintainers and hackage trustees


Readme for exon-0.1.0.0

[back to package description]

This Haskell library provides quasiquote string interpolation with customizable concatenation for arbitrary types.

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.

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.