{-# LANGUAGE FlexibleInstances, UndecidableInstances, FunctionalDependencies #-} module Data.Text.Human.Parse ( HumanParse (..) ) where import Data.Bool (Bool (..)) import Data.Either (Either (..)) import Data.Maybe (Maybe (..)) import Data.Text (Text) import Data.Void (Void) import qualified Data.Char as C import qualified Data.Text as T -- | An unprincipled best-effort informal attempt to figure out what a human is -- saying. -- -- Type variables: -- -- * @a@ - The type we're trying to parse into -- * @e@ - The type of error we produce when we can't understand the human class HumanParse e a | a -> e where parseHuman :: Text -> Either e a instance HumanParse () Void where parseHuman _ = Left () -- | We parse @'Maybe' a@ by first attempting to parse @a@ and wrap it in -- @Just@. If that fails but the input is only whitespace, then we accept the -- as @Nothing@. If there is some /non/-whitespace text that fails to parse as -- @a@, only then do we reject the input. instance HumanParse e a => HumanParse e (Maybe a) where parseHuman t = case parseHuman t of Right a -> Right (Just a) Left _ | isWhitespace t -> Right Nothing Left e -> Left e isWhitespace :: Text -> Bool isWhitespace = T.all C.isSpace