{-# LANGUAGE DataKinds #-}
{-# LANGUAGE DeriveAnyClass #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE DerivingStrategies #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE UndecidableInstances #-}

module Taiwan.ID.Letter
  ( Letter (..)
  , fromChar
  , toChar
  , generate
  , FromChar
  ) where

import Control.Monad.Random.Class
  ( MonadRandom (..) )
import Data.Finitary
  ( Finitary )
import GHC.Generics
  ( Generic )
import Taiwan.ID.Utilities
  ( randomFinitary )
import Text.Read
  ( readMaybe )

-- | Represents a letter in the latin alphabet.
--
data Letter
  = A | B | C | D | E | F | G | H | I | J | K | L | M
  | N | O | P | Q | R | S | T | U | V | W | X | Y | Z
  deriving stock (Letter
Letter -> Letter -> Bounded Letter
forall a. a -> a -> Bounded a
$cminBound :: Letter
minBound :: Letter
$cmaxBound :: Letter
maxBound :: Letter
Bounded, Int -> Letter
Letter -> Int
Letter -> [Letter]
Letter -> Letter
Letter -> Letter -> [Letter]
Letter -> Letter -> Letter -> [Letter]
(Letter -> Letter)
-> (Letter -> Letter)
-> (Int -> Letter)
-> (Letter -> Int)
-> (Letter -> [Letter])
-> (Letter -> Letter -> [Letter])
-> (Letter -> Letter -> [Letter])
-> (Letter -> Letter -> Letter -> [Letter])
-> Enum Letter
forall a.
(a -> a)
-> (a -> a)
-> (Int -> a)
-> (a -> Int)
-> (a -> [a])
-> (a -> a -> [a])
-> (a -> a -> [a])
-> (a -> a -> a -> [a])
-> Enum a
$csucc :: Letter -> Letter
succ :: Letter -> Letter
$cpred :: Letter -> Letter
pred :: Letter -> Letter
$ctoEnum :: Int -> Letter
toEnum :: Int -> Letter
$cfromEnum :: Letter -> Int
fromEnum :: Letter -> Int
$cenumFrom :: Letter -> [Letter]
enumFrom :: Letter -> [Letter]
$cenumFromThen :: Letter -> Letter -> [Letter]
enumFromThen :: Letter -> Letter -> [Letter]
$cenumFromTo :: Letter -> Letter -> [Letter]
enumFromTo :: Letter -> Letter -> [Letter]
$cenumFromThenTo :: Letter -> Letter -> Letter -> [Letter]
enumFromThenTo :: Letter -> Letter -> Letter -> [Letter]
Enum, Letter -> Letter -> Bool
(Letter -> Letter -> Bool)
-> (Letter -> Letter -> Bool) -> Eq Letter
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: Letter -> Letter -> Bool
== :: Letter -> Letter -> Bool
$c/= :: Letter -> Letter -> Bool
/= :: Letter -> Letter -> Bool
Eq, (forall x. Letter -> Rep Letter x)
-> (forall x. Rep Letter x -> Letter) -> Generic Letter
forall x. Rep Letter x -> Letter
forall x. Letter -> Rep Letter x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cfrom :: forall x. Letter -> Rep Letter x
from :: forall x. Letter -> Rep Letter x
$cto :: forall x. Rep Letter x -> Letter
to :: forall x. Rep Letter x -> Letter
Generic, Eq Letter
Eq Letter =>
(Letter -> Letter -> Ordering)
-> (Letter -> Letter -> Bool)
-> (Letter -> Letter -> Bool)
-> (Letter -> Letter -> Bool)
-> (Letter -> Letter -> Bool)
-> (Letter -> Letter -> Letter)
-> (Letter -> Letter -> Letter)
-> Ord Letter
Letter -> Letter -> Bool
Letter -> Letter -> Ordering
Letter -> Letter -> Letter
forall a.
Eq a =>
(a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
$ccompare :: Letter -> Letter -> Ordering
compare :: Letter -> Letter -> Ordering
$c< :: Letter -> Letter -> Bool
< :: Letter -> Letter -> Bool
$c<= :: Letter -> Letter -> Bool
<= :: Letter -> Letter -> Bool
$c> :: Letter -> Letter -> Bool
> :: Letter -> Letter -> Bool
$c>= :: Letter -> Letter -> Bool
>= :: Letter -> Letter -> Bool
$cmax :: Letter -> Letter -> Letter
max :: Letter -> Letter -> Letter
$cmin :: Letter -> Letter -> Letter
min :: Letter -> Letter -> Letter
Ord, ReadPrec [Letter]
ReadPrec Letter
Int -> ReadS Letter
ReadS [Letter]
(Int -> ReadS Letter)
-> ReadS [Letter]
-> ReadPrec Letter
-> ReadPrec [Letter]
-> Read Letter
forall a.
(Int -> ReadS a)
-> ReadS [a] -> ReadPrec a -> ReadPrec [a] -> Read a
$creadsPrec :: Int -> ReadS Letter
readsPrec :: Int -> ReadS Letter
$creadList :: ReadS [Letter]
readList :: ReadS [Letter]
$creadPrec :: ReadPrec Letter
readPrec :: ReadPrec Letter
$creadListPrec :: ReadPrec [Letter]
readListPrec :: ReadPrec [Letter]
Read, Int -> Letter -> ShowS
[Letter] -> ShowS
Letter -> String
(Int -> Letter -> ShowS)
-> (Letter -> String) -> ([Letter] -> ShowS) -> Show Letter
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> Letter -> ShowS
showsPrec :: Int -> Letter -> ShowS
$cshow :: Letter -> String
show :: Letter -> String
$cshowList :: [Letter] -> ShowS
showList :: [Letter] -> ShowS
Show)
  deriving anyclass Eq Letter
KnownNat (Cardinality Letter)
(Eq Letter, KnownNat (Cardinality Letter)) =>
(Finite (Cardinality Letter) -> Letter)
-> (Letter -> Finite (Cardinality Letter))
-> ((1 <= Cardinality Letter) => Letter)
-> ((1 <= Cardinality Letter) => Letter)
-> (Letter -> Maybe Letter)
-> (Letter -> Maybe Letter)
-> Finitary Letter
(1 <= Cardinality Letter) => Letter
Finite (Cardinality Letter) -> Letter
Letter -> Maybe Letter
Letter -> Finite (Cardinality Letter)
forall a.
(Eq a, KnownNat (Cardinality a)) =>
(Finite (Cardinality a) -> a)
-> (a -> Finite (Cardinality a))
-> ((1 <= Cardinality a) => a)
-> ((1 <= Cardinality a) => a)
-> (a -> Maybe a)
-> (a -> Maybe a)
-> Finitary a
$cfromFinite :: Finite (Cardinality Letter) -> Letter
fromFinite :: Finite (Cardinality Letter) -> Letter
$ctoFinite :: Letter -> Finite (Cardinality Letter)
toFinite :: Letter -> Finite (Cardinality Letter)
$cstart :: (1 <= Cardinality Letter) => Letter
start :: (1 <= Cardinality Letter) => Letter
$cend :: (1 <= Cardinality Letter) => Letter
end :: (1 <= Cardinality Letter) => Letter
$cprevious :: Letter -> Maybe Letter
previous :: Letter -> Maybe Letter
$cnext :: Letter -> Maybe Letter
next :: Letter -> Maybe Letter
Finitary

-- | Attempts to parse a 'Letter' from a character.
--
-- Returns 'Nothing' if the specified character is not an uppercase alphabetic
-- character.
--
fromChar :: Char -> Maybe Letter
fromChar :: Char -> Maybe Letter
fromChar Char
c = String -> Maybe Letter
forall a. Read a => String -> Maybe a
readMaybe [Char
c]

-- | Converts the specified 'Letter' to a character.
--
toChar :: Letter -> Char
toChar :: Letter -> Char
toChar Letter
letter = case Letter -> String
forall a. Show a => a -> String
show Letter
letter of
  [Char
c] -> Char
c
  String
_ -> String -> Char
forall a. HasCallStack => String -> a
error String
"toChar"

-- | Generates a random 'Letter'.
--
generate :: MonadRandom m => m Letter
generate :: forall (m :: * -> *). MonadRandom m => m Letter
generate = m Letter
forall (m :: * -> *) a.
(MonadRandom m, Finitary a, 1 <= Cardinality a) =>
m a
randomFinitary

type family FromChar (c :: Char) :: Maybe Letter where
  FromChar 'A' = Just A; FromChar 'N' = Just N
  FromChar 'B' = Just B; FromChar 'O' = Just O
  FromChar 'C' = Just C; FromChar 'P' = Just P
  FromChar 'D' = Just D; FromChar 'Q' = Just Q
  FromChar 'E' = Just E; FromChar 'R' = Just R
  FromChar 'F' = Just F; FromChar 'S' = Just S
  FromChar 'G' = Just G; FromChar 'T' = Just T
  FromChar 'H' = Just H; FromChar 'U' = Just U
  FromChar 'I' = Just I; FromChar 'V' = Just V
  FromChar 'J' = Just J; FromChar 'W' = Just W
  FromChar 'K' = Just K; FromChar 'X' = Just X
  FromChar 'L' = Just L; FromChar 'Y' = Just Y
  FromChar 'M' = Just M; FromChar 'Z' = Just Z
  FromChar _ = Nothing