{-# LANGUAGE NoImplicitPrelude #-} {-# LANGUAGE TemplateHaskell #-} {-# LANGUAGE RankNTypes #-} module Data.Char.Alpha( -- * Upper-case AlphaUpper , HasAlphaUpper(alphaUpper) , AsAlphaUpper(_AlphaUpper) , parseAlphaUpper -- * Lower-case , AlphaLower , HasAlphaLower(alphaLower) , AsAlphaLower(_AlphaLower) , parseAlphaLower -- * Any case , Alpha(UpperAlpha, LowerAlpha) , HasAlpha(alpha) , AsAlpha(_Alpha, _UpperAlpha, _LowerAlpha) , parseAlpha -- * Accessory , upperlower , lowerupper ) where import Control.Applicative((<$>), (<|>), empty) import Control.Category((.), id) import Control.Lens(makeClassy, makeClassyPrisms, from, iso, prism', (^?), Iso', Prism') import Control.Monad(Monad((>>=), return)) import Data.Char(Char, toLower, toUpper) import Data.Eq(Eq) import Data.Foldable(elem) import Data.Maybe(Maybe(Just, Nothing), maybe) import Data.Ord(Ord) import Prelude(Show) import Text.Parser.Char(CharParsing, anyChar) import Text.Parser.Combinators((), try) -- $setup -- -- >>> import Text.Parsec(parse) -- | An upper-case character between @'A'@ and @'Z'@. newtype AlphaUpper = AlphaUpper Char deriving (Eq, Ord, Show) makeClassy ''AlphaUpper class AsAlphaUpper a where _AlphaUpper :: Prism' a AlphaUpper instance AsAlphaUpper AlphaUpper where _AlphaUpper = id instance AsAlphaUpper Char where _AlphaUpper = prism' (\(AlphaUpper c) -> c) (\c -> if c `elem` ['A'..'Z'] then Just (AlphaUpper c) else Nothing) -- | Parse an upper-case alpha character. -- -- >>> parse parseAlphaUpper "parseAlphaUpper" "A" -- Right (AlphaUpper 'A') -- -- >>> parse parseAlphaUpper "parseAlphaUpper" "Abc" -- Right (AlphaUpper 'A') -- -- >>> isn't _Right (parse parseAlphaUpper "parseAlphaUpper" "a") -- True -- -- >>> isn't _Right (parse parseAlphaUpper "parseAlphaUpper" "") -- True -- -- >>> isn't _Right (parse parseAlphaUpper "parseAlphaUpper" "0") -- True parseAlphaUpper :: (Monad f, CharParsing f) => f AlphaUpper parseAlphaUpper = try (anyChar >>= \c -> maybe empty return (c ^? _AlphaUpper)) "AlphaUpper" -- | A lower-case character between @'a'@ and @'z'@. newtype AlphaLower = AlphaLower Char deriving (Eq, Ord, Show) makeClassy ''AlphaLower class AsAlphaLower a where _AlphaLower :: Prism' a AlphaLower instance AsAlphaLower AlphaLower where _AlphaLower = id instance AsAlphaLower Char where _AlphaLower = prism' (\(AlphaLower c) -> c) (\c -> if c `elem` ['a'..'z'] then Just (AlphaLower c) else Nothing) -- | Parse a lower-case alpha character. -- -- >>> parse parseAlphaLower "parseAlphaLower" "a" -- Right (AlphaLower 'a') -- -- >>> parse parseAlphaLower "parseAlphaLower" "aBC" -- Right (AlphaLower 'a') -- -- >>> isn't _Right (parse parseAlphaLower "parseAlphaLower" "B") -- True -- -- >>> isn't _Right (parse parseAlphaLower "parseAlphaLower" "") -- True -- -- >>> isn't _Right (parse parseAlphaLower "parseAlphaLower" "0") -- True parseAlphaLower :: (Monad f, CharParsing f) => f AlphaLower parseAlphaLower = try (anyChar >>= \c -> maybe empty return (c ^? _AlphaLower)) "AlphaLower" -- | Either a lower-case character between @'a'@ and @'z'@ or an upper-case character between @'A'@ and @'Z'@. data Alpha = UpperAlpha AlphaUpper | LowerAlpha AlphaLower deriving (Eq, Ord, Show) makeClassyPrisms ''Alpha makeClassy ''Alpha -- | Parse an upper-case or lower-case character. -- -- >>> parse parseAlpha "parseAlpha" "a" -- Right (LowerAlpha (AlphaLower 'a')) -- -- >>> parse parseAlpha "parseAlpha" "aBC" -- Right (LowerAlpha (AlphaLower 'a')) -- -- >>> parse parseAlpha "parseAlpha" "A" -- Right (UpperAlpha (AlphaUpper 'A')) -- -- >>> parse parseAlpha "parseAlpha" "Abc" -- Right (UpperAlpha (AlphaUpper 'A')) -- -- >>> isn't _Right (parse parseAlpha "parseAlpha" "0") -- True parseAlpha :: (Monad f, CharParsing f) => f Alpha parseAlpha = UpperAlpha <$> parseAlphaUpper <|> LowerAlpha <$> parseAlphaLower instance AsAlphaLower Alpha where _AlphaLower = _LowerAlpha . _AlphaLower instance AsAlphaUpper Alpha where _AlphaUpper = _UpperAlpha . _AlphaUpper -- | Isomorphism from upper to lower. -- -- >>> (upperlower #) <$> ('a' ^? _AlphaLower) -- Just (AlphaUpper 'A') -- -- >>> (upperlower #) <$> ('A' ^? _AlphaLower) -- Nothing -- -- >>> (upperlower #) <$> ('3' ^? _AlphaLower) -- Nothing upperlower :: Iso' AlphaUpper AlphaLower upperlower = iso (\(AlphaUpper c) -> AlphaLower (toLower c)) (\(AlphaLower c) -> AlphaUpper (toUpper c)) -- | Isomorphism from lower to upper. -- -- >>> (lowerupper #) <$> ('A' ^? _AlphaUpper) -- Just (AlphaLower 'a') -- -- >>> (lowerupper #) <$> ('a' ^? _AlphaUpper) -- Nothing -- -- >>> (lowerupper #) <$> ('3' ^? _AlphaUpper) -- Nothing lowerupper :: Iso' AlphaLower AlphaUpper lowerupper = from upperlower