packages feed

casa-reoc-0.1.0.0: src/ReOC/Primitive/Postcode.hs

{-# LANGUAGE DeriveLift #-}
{-# OPTIONS_GHC -Wall #-}

{- | An Australian postcode: 4 digits.

The constructor is not exported (see "ReOC.Primitive.Text1"). A @Postcode@
is built with the prism '_Postcode' or with 'postcodeLiteral'.
-}
module ReOC.Primitive.Postcode (
  Postcode,
  _Postcode,
  postcodeText,
  postcodeLiteral,
) where

import Control.Lens (Prism', preview, prism')
import Data.Char (isDigit)
import Data.Text (Text)
import qualified Data.Text as Text
import Language.Haskell.TH.Syntax (Code (..), Lift, Q, liftTyped)

{- $setup
>>> :set -XOverloadedStrings
>>> import Control.Lens ((^?))
-}

-- | An Australian postcode.
newtype Postcode
  = Postcode Text
  deriving (Eq, Ord, Show, Lift)

{- | A postcode from its 4 digits.

>>> "4000" ^? _Postcode
Just (Postcode "4000")

>>> "400" ^? _Postcode
Nothing
-}
_Postcode :: Prism' Text Postcode
_Postcode =
  prism'
    postcodeText
    (\t -> if Text.length t == 4 && Text.all isDigit t then Just (Postcode t) else Nothing)

-- | The 4 digits of a postcode.
postcodeText :: Postcode -> Text
postcodeText (Postcode t) =
  t

{- | A @Postcode@ literal, checked when the program is compiled:

> $$(postcodeLiteral "4000")
-}
postcodeLiteral :: String -> Code Q Postcode
postcodeLiteral s =
  maybe
    (Code (fail ("postcodeLiteral: not a postcode: " <> show s)))
    liftTyped
    (preview _Postcode (Text.pack s))