{-# LANGUAGE DataKinds #-} {-# LANGUAGE PolyKinds #-} {-# LANGUAGE TypeFamilies #-} {-# LANGUAGE TypeInType #-} {-# LANGUAGE TypeOperators #-} {-# LANGUAGE UndecidableInstances #-} {-# OPTIONS_GHC -Wall #-} {-# OPTIONS_GHC -Werror=incomplete-patterns #-} {-| Module : Fcf.Data.Text Description : Type-level Text data structure with methods Copyright : (c) gspia 2020- License : BSD Maintainer : gspia = Fcf.Data.Text We mimick Data.Text but on type level. The internal representation is based on type level lists. -} -------------------------------------------------------------------------------- module Fcf.Data.Text ( Text (..) -- * Creation , Empty , Singleton , FromList , ToList , ToSymbol -- * Basic Interface , Null , Length , Append , Cons , Snoc , Uncons , Unsnoc , Head , Tail , Init , CompareLength -- * Transformation , Map , Intercalate , Intersperse , Reverse , Replace -- * Special Folds , Concat , ConcatMap , Any , All -- * Substrings , Take , TakeEnd , Drop , DropEnd , TakeWhile , TakeWhileEnd , DropWhile , DropWhileEnd , DropAround , Strip -- * Breaking etc , SplitOn , Split , Lines , Words , Unlines , Unwords -- * Predicates , IsPrefixOf , IsSuffixOf , IsInfixOf ) where import qualified GHC.TypeLits as TL import Fcf ( If, Eval, Exp, type (=<<), type (@@) , Flip, Pure ) import Fcf.Data.List ( type (++) ) import qualified Fcf.Data.List as F ( Length, Head, Tail, Init, Reverse, Take, Drop, TakeWhile, DropWhile , Foldr) import qualified Fcf.Classes as F ( Map ) import qualified Fcf.Alg.List as F ( Any, All, IsPrefixOf, IsSuffixOf, IsInfixOf, Snoc, Intercalate , Intersperse) import Fcf.Data.Nat (Nat) import Fcf.Alg.Morphism (First,Second) import Fcf.Data.Symbol (Symbol) import qualified Fcf.Data.Symbol as S -------------------------------------------------------------------------------- -- For the doctests: -- $setup -- >>> import Fcf (type (<=<), Not) -------------------------------------------------------------------------------- -- | 'Text' is a data structure, that is, a list to hold type-level symbols of -- length one. data Text = Text [Symbol] -------------------------------------------------------------------------------- -- | Empty -- -- === __Example__ -- -- >>> :kind! (Eval Empty :: Text) -- (Eval Empty :: Text) :: Text -- = 'Text '[] -- -- See also the other examples in this module. data Empty :: Exp Text type instance Eval Empty = 'Text '[] -- | Singleton -- -- === __Example__ -- -- >>> :kind! Eval (Singleton "a") -- Eval (Singleton "a") :: Text -- = 'Text '["a"] data Singleton :: Symbol -> Exp Text type instance Eval (Singleton s) = 'Text '[s] -- | Use FromList to construct a Text from type-level list. -- -- === __Example__ -- -- :kind! Eval (FromList '["h", "e", "l", "l", "u", "r", "e", "i"]) -- Eval (FromList '["h", "e", "l", "l", "u", "r", "e", "i"]) :: Text -- = 'Text '["h", "e", "l", "l", "u", "r", "e", "i"] data FromList :: [Symbol] -> Exp Text type instance Eval (FromList lst) = 'Text lst -- | Get the type-level list out of the 'Text'. -- -- === __Example__ -- -- >>> :kind! Eval (ToList =<< FromList '["a", "b"]) -- Eval (ToList =<< FromList '["a", "b"]) :: [Symbol] -- = '["a", "b"] data ToList :: Text -> Exp [Symbol] type instance Eval (ToList ('Text lst)) = lst -- | ToSymbol -- -- === __Example__ -- -- >>> :kind! Eval (ToSymbol =<< FromList '["w", "o", "r", "d"]) -- Eval (ToSymbol =<< FromList '["w", "o", "r", "d"]) :: Symbol -- = "word" data ToSymbol :: Text -> Exp Symbol type instance Eval (ToSymbol ('Text lst)) = Eval (F.Foldr S.Append "" lst) -- | Null -- -- === __Example__ -- -- >>> :kind! Eval (Null =<< FromList '["a", "b"]) -- Eval (Null =<< FromList '["a", "b"]) :: Bool -- = 'False -- >>> :kind! Eval (Null =<< Empty) -- Eval (Null =<< Empty) :: Bool -- = 'True data Null :: Text -> Exp Bool type instance Eval (Null ('Text '[])) = 'True type instance Eval (Null ('Text (_ ': _))) = 'False -- | Length -- -- === __Example__ -- -- >>> :kind! Eval (Length =<< FromList '["a", "b"]) -- Eval (Length =<< FromList '["a", "b"]) :: Nat -- = 2 data Length :: Text -> Exp Nat type instance Eval (Length ('Text lst)) = Eval (F.Length lst) -- | Add a symbol to the beginning of a type-level text. -- -- === __Example__ -- -- > :kind! Eval (Cons "h" ('Text '["a", "a", "m", "u"])) -- Eval (Cons "h" ('Text '["a", "a", "m", "u"])) :: Text -- = 'Text '["h", "a", "a", "m", "u"] data Cons :: Symbol -> Text -> Exp Text type instance Eval (Cons s ('Text lst)) = 'Text (s ': lst) -- | Add a symbol to the end of a type-level text. -- -- === __Example__ -- -- >>> :kind! Eval (Snoc ('Text '["a", "a", "m"]) "u") -- Eval (Snoc ('Text '["a", "a", "m"]) "u") :: Text -- = 'Text '["a", "a", "m", "u"] data Snoc :: Text -> Symbol -> Exp Text type instance Eval (Snoc ('Text lst) s) = 'Text (Eval (lst ++ '[s])) -- | Append two type-level texts. -- -- === __Example__ -- -- >>> :kind! Eval (Append ('Text '["a", "a"]) ('Text '["m", "u"])) -- Eval (Append ('Text '["a", "a"]) ('Text '["m", "u"])) :: Text -- = 'Text '["a", "a", "m", "u"] data Append :: Text -> Text -> Exp Text type instance Eval (Append ('Text l1) ('Text l2)) = 'Text (Eval (l1 ++ l2)) -- | Get the first symbol from type-level text. -- -- === __Example__ -- -- >>> :kind! Eval (Uncons ('Text '["h", "a", "a", "m", "u"])) -- Eval (Uncons ('Text '["h", "a", "a", "m", "u"])) :: Maybe -- (Symbol, Text) -- = 'Just '("h", 'Text '["a", "a", "m", "u"]) -- -- >>> :kind! Eval (Uncons ('Text '[])) -- Eval (Uncons ('Text '[])) :: Maybe (Symbol, Text) -- = 'Nothing data Uncons :: Text -> Exp (Maybe (Symbol, Text)) type instance Eval (Uncons ('Text '[])) = 'Nothing type instance Eval (Uncons ('Text (t ': txt))) = 'Just '(t, 'Text txt) -- | Get the last symbol from type-level text. -- -- === __Example__ -- -- >>> :kind! Eval (Unsnoc ('Text '["a", "a", "m", "u", "n"])) -- Eval (Unsnoc ('Text '["a", "a", "m", "u", "n"])) :: Maybe -- (Symbol, Text) -- = 'Just '("n", 'Text '["a", "a", "m", "u"]) -- -- >>> :kind! Eval (Unsnoc ('Text '[])) -- Eval (Unsnoc ('Text '[])) :: Maybe (Symbol, Text) -- = 'Nothing data Unsnoc :: Text -> Exp (Maybe (Symbol, Text)) type instance Eval (Unsnoc txt) = Eval (F.Map (Second Reverse) =<< Uncons =<< Reverse txt) -- | Get the first symbol of type-level text. -- -- === __Example__ -- -- >>> :kind! Eval (Head ('Text '["a", "a", "m", "u"])) -- Eval (Head ('Text '["a", "a", "m", "u"])) :: Maybe Symbol -- = 'Just "a" -- -- >>> :kind! Eval (Head ('Text '[])) -- Eval (Head ('Text '[])) :: Maybe Symbol -- = 'Nothing data Head :: Text -> Exp (Maybe Symbol) type instance Eval (Head ('Text lst)) = Eval (F.Head lst) -- | Get the tail of a type-level text. -- -- === __Example__ -- -- >>> :kind! Eval (Tail ('Text '["h", "a", "a", "m", "u"])) -- Eval (Tail ('Text '["h", "a", "a", "m", "u"])) :: Maybe Text -- = 'Just ('Text '["a", "a", "m", "u"]) -- -- >>> :kind! Eval (Tail ('Text '[])) -- Eval (Tail ('Text '[])) :: Maybe Text -- = 'Nothing data Tail :: Text -> Exp (Maybe Text) type instance Eval (Tail ('Text lst)) = Eval (F.Map FromList =<< F.Tail lst) -- | Take all except the last symbol from type-level text. -- -- === __Example__ -- -- >>> :kind! Eval (Init ('Text '["a", "a", "m", "u", "n"])) -- Eval (Init ('Text '["a", "a", "m", "u", "n"])) :: Maybe Text -- = 'Just ('Text '["a", "a", "m", "u"]) -- -- >>> :kind! Eval (Init ('Text '[])) -- Eval (Init ('Text '[])) :: Maybe Text -- = 'Nothing data Init :: Text -> Exp (Maybe Text) type instance Eval (Init ('Text lst)) = Eval (F.Map FromList =<< F.Init lst) -- | Compare the length of type-level text to given Nat and give -- the Ordering. -- -- === __Example__ -- -- >>> :kind! Eval (CompareLength ('Text '["a", "a", "m", "u"]) 3) -- Eval (CompareLength ('Text '["a", "a", "m", "u"]) 3) :: Ordering -- = 'GT data CompareLength :: Text -> Nat -> Exp Ordering type instance Eval (CompareLength txt n) = TL.CmpNat (Length @@ txt) n -- | Map for type-level text. -- -- === __Example__ -- -- >>> :{ -- data IsIsymb :: Symbol -> Exp Bool -- type instance Eval (IsIsymb s) = Eval ("i" S.== s) -- data Isymb2e :: Symbol -> Exp Symbol -- type instance Eval (Isymb2e s) = Eval -- (If (IsIsymb @@ s) -- (Pure "e") -- (Pure s) -- ) -- :} -- -- >>> :kind! Eval (Map Isymb2e ('Text '["i","m","u"])) -- Eval (Map Isymb2e ('Text '["i","m","u"])) :: Text -- = 'Text '["e", "m", "u"] data Map :: (Symbol -> Exp Symbol) -> Text -> Exp Text type instance Eval (Map f ('Text lst)) = 'Text (Eval (F.Map f lst)) -- | Intercalate for type-level text. -- -- === __Example__ -- -- >>> :kind! Eval (Intercalate ('Text '[" ", "&", " "]) ('[ 'Text '["a", "a", "m", "u"], 'Text '["v", "a", "l", "o"]])) -- Eval (Intercalate ('Text '[" ", "&", " "]) ('[ 'Text '["a", "a", "m", "u"], 'Text '["v", "a", "l", "o"]])) :: Text -- = 'Text '["a", "a", "m", "u", " ", "&", " ", "v", "a", "l", "o"] data Intercalate :: Text -> [Text] -> Exp Text type instance Eval (Intercalate ('Text txt) txts) = Eval (FromList =<< F.Intercalate txt =<< F.Map ToList txts) -- | Intersperse for type-level text. -- -- === __Example__ -- -- >>> :kind! Eval (Intersperse "." ('Text '["a", "a", "m", "u"])) -- Eval (Intersperse "." ('Text '["a", "a", "m", "u"])) :: Text -- = 'Text '["a", ".", "a", ".", "m", ".", "u"] data Intersperse :: Symbol -> Text -> Exp Text type instance Eval (Intersperse s ('Text txt)) = Eval (FromList =<< F.Intersperse s txt) -- | Reverse for type-level text. -- -- === __Example__ -- -- >>> :kind! Eval (Reverse ('Text '["a", "a", "m", "u"])) -- Eval (Reverse ('Text '["a", "a", "m", "u"])) :: Text -- = 'Text '["u", "m", "a", "a"] -- -- >>> :kind! Eval (Reverse =<< Reverse ('Text '["a", "a", "m", "u"])) -- Eval (Reverse =<< Reverse ('Text '["a", "a", "m", "u"])) :: Text -- = 'Text '["a", "a", "m", "u"] data Reverse :: Text -> Exp Text type instance Eval (Reverse ('Text lst)) = 'Text (Eval (F.Reverse lst)) -- | Replace for type-level text. -- -- === __Example__ -- -- >>> :kind! Eval (Replace ('Text '["t","u"]) ('Text '["l","a"]) ('Text '["t","u","u","t","u","t","t","a","a"])) -- Eval (Replace ('Text '["t","u"]) ('Text '["l","a"]) ('Text '["t","u","u","t","u","t","t","a","a"])) :: Text -- = 'Text '["l", "a", "u", "l", "a", "t", "t", "a", "a"] data Replace :: Text -> Text -> Text -> Exp Text type instance Eval (Replace orig new txt) = Eval (Intercalate new =<< SplitOn orig txt) -- | Concat for type-level text. -- -- === __Example__ -- -- >>> :kind! Eval (Concat '[ 'Text '["l","a"], 'Text '["k","a","n","a"]]) -- Eval (Concat '[ 'Text '["l","a"], 'Text '["k","a","n","a"]]) :: Text -- = 'Text '["l", "a", "k", "a", "n", "a"] data Concat :: [Text] -> Exp Text type instance Eval (Concat lst) = Eval (F.Foldr Append (Eval Empty :: Text) lst) -- | ConcatMap for type-level text. -- -- === __Example__ -- -- >>> :{ -- data IsIsymb :: Symbol -> Exp Bool -- type instance Eval (IsIsymb s) = Eval ("i" S.== s) -- data Isymb2aa :: Symbol -> Exp Text -- type instance Eval (Isymb2aa s) = Eval -- (If (IsIsymb @@ s) -- (Pure ('Text '["a","a"])) -- (Pure ('Text '[s])) -- ) -- :} -- -- >>> :kind! Eval (ConcatMap Isymb2aa ('Text '["i","m","u"," ","i","h"])) -- Eval (ConcatMap Isymb2aa ('Text '["i","m","u"," ","i","h"])) :: Text -- = 'Text '["a", "a", "m", "u", " ", "a", "a", "h"] data ConcatMap :: (Symbol -> Exp Text) -> Text -> Exp Text type instance Eval (ConcatMap f ('Text lst)) = Eval (Concat =<< F.Map f lst) -- | Any for type-level text. -- -- === __Example__ -- -- >>> :kind! Eval (Any S.IsDigit ('Text '["a","a","m","u","1"])) -- Eval (Any S.IsDigit ('Text '["a","a","m","u","1"])) :: Bool -- = 'True -- -- >>> :kind! Eval (Any S.IsDigit ('Text '["a","a","m","u"])) -- Eval (Any S.IsDigit ('Text '["a","a","m","u"])) :: Bool -- = 'False data Any :: (Symbol -> Exp Bool) -> Text -> Exp Bool type instance Eval (Any f ('Text lst)) = Eval (F.Any f lst) -- | All for type-level text. -- -- === __Example__ -- -- >>> :kind! Eval (All S.IsDigit ('Text '["a","a","m","u","1"])) -- Eval (All S.IsDigit ('Text '["a","a","m","u","1"])) :: Bool -- = 'False -- -- >>> :kind! Eval (All S.IsDigit ('Text '["3","2","1"])) -- Eval (All S.IsDigit ('Text '["3","2","1"])) :: Bool -- = 'True data All :: (Symbol -> Exp Bool) -> Text -> Exp Bool type instance Eval (All f ('Text lst)) = Eval (F.All f lst) -- | Take for type-level text. -- -- === __Example__ -- -- >>> :kind! Eval (Take 4 ('Text '["a", "a", "m", "u", "n"])) -- Eval (Take 4 ('Text '["a", "a", "m", "u", "n"])) :: Text -- = 'Text '["a", "a", "m", "u"] data Take :: Nat -> Text -> Exp Text type instance Eval (Take n ('Text lst)) = 'Text (Eval (F.Take n lst)) -- | TakeEnd for type-level text. -- -- === __Example__ -- -- >>> :kind! Eval (TakeEnd 4 ('Text '["h", "a", "a", "m", "u"])) -- Eval (TakeEnd 4 ('Text '["h", "a", "a", "m", "u"])) :: Text -- = 'Text '["a", "a", "m", "u"] data TakeEnd :: Nat -> Text -> Exp Text type instance Eval (TakeEnd n ('Text lst)) = 'Text (Eval (F.Reverse =<< F.Take n =<< F.Reverse lst)) -- | Drop for type-level text. -- -- === __Example__ -- -- >>> :kind! Eval (Drop 2 ('Text '["a", "a", "m", "u", "n", "a"])) -- Eval (Drop 2 ('Text '["a", "a", "m", "u", "n", "a"])) :: Text -- = 'Text '["m", "u", "n", "a"] data Drop :: Nat -> Text -> Exp Text type instance Eval (Drop n ('Text lst)) = 'Text (Eval (F.Drop n lst)) -- | DropEnd for type-level text. -- -- === __Example__ -- -- >>> :kind! Eval (DropEnd 2 ('Text '["a", "a", "m", "u", "n", "a"])) -- Eval (DropEnd 2 ('Text '["a", "a", "m", "u", "n", "a"])) :: Text -- = 'Text '["a", "a", "m", "u"] data DropEnd :: Nat -> Text -> Exp Text type instance Eval (DropEnd n ('Text lst)) = 'Text (Eval (F.Reverse =<< F.Drop n =<< F.Reverse lst)) -- | TakeWhile for type-level text. -- -- === __Example__ -- -- >>> :kind! Eval (TakeWhile (Not <=< S.IsDigit) ('Text '["a","a","m","u","1","2"])) -- Eval (TakeWhile (Not <=< S.IsDigit) ('Text '["a","a","m","u","1","2"])) :: Text -- = 'Text '["a", "a", "m", "u"] data TakeWhile :: (Symbol -> Exp Bool) -> Text -> Exp Text type instance Eval (TakeWhile f ('Text lst)) = 'Text (Eval (F.TakeWhile f lst)) -- | TakeWhileEnd for type-level text. -- -- === __Example__ -- -- >>> :kind! Eval (TakeWhileEnd (Not <=< S.IsDigit) ('Text '["1","2","a","a","m","u"])) -- Eval (TakeWhileEnd (Not <=< S.IsDigit) ('Text '["1","2","a","a","m","u"])) :: Text -- = 'Text '["a", "a", "m", "u"] data TakeWhileEnd :: (Symbol -> Exp Bool) -> Text -> Exp Text type instance Eval (TakeWhileEnd f ('Text lst)) = 'Text (Eval (F.Reverse =<< F.TakeWhile f =<< F.Reverse lst)) -- | DropWhile for type-level text. -- -- === __Example__ -- -- >>> :kind! Eval (DropWhile S.IsDigit ('Text '["1","2","a","a","m","u"])) -- Eval (DropWhile S.IsDigit ('Text '["1","2","a","a","m","u"])) :: Text -- = 'Text '["a", "a", "m", "u"] data DropWhile :: (Symbol -> Exp Bool) -> Text -> Exp Text type instance Eval (DropWhile f ('Text lst)) = 'Text (Eval (F.DropWhile f lst)) -- | DropWhileEnd for type-level text. -- === __Example__ -- -- >>> :kind! Eval (DropWhileEnd S.IsDigit ('Text '["a","a","m","u","1","2"])) -- Eval (DropWhileEnd S.IsDigit ('Text '["a","a","m","u","1","2"])) :: Text -- = 'Text '["a", "a", "m", "u"] data DropWhileEnd :: (Symbol -> Exp Bool) -> Text -> Exp Text type instance Eval (DropWhileEnd f ('Text lst)) = 'Text (Eval (F.Reverse =<< F.DropWhile f =<< F.Reverse lst)) -- | DropAround for type-level text. -- -- === __Example__ -- -- >>> :kind! Eval (DropAround S.IsDigit ('Text '["3","4","a","a","m","u","1","2"])) -- Eval (DropAround S.IsDigit ('Text '["3","4","a","a","m","u","1","2"])) :: Text -- = 'Text '["a", "a", "m", "u"] data DropAround :: (Symbol -> Exp Bool) -> Text -> Exp Text type instance Eval (DropAround f txt) = Eval (DropWhile f =<< DropWhileEnd f txt) -- | Strip the space, newline and tab -symbols from the beginning and and -- of type-level text. -- -- === __Example__ -- -- >>> :kind! Eval (Strip ('Text '[" ", " ", "a", "a", "m", "u", " ", "\n"])) -- Eval (Strip ('Text '[" ", " ", "a", "a", "m", "u", " ", "\n"])) :: Text -- = 'Text '["a", "a", "m", "u"] data Strip :: Text -> Exp Text type instance Eval (Strip txt) = Eval (DropAround S.IsSpaceDelim txt) -- | SplitOn for type-level text. -- -- === __Example__ -- -- >>> :kind! Eval (SplitOn (Eval (FromList '["a", "b"])) (Eval (FromList '[ "c", "d", "a", "b", "f", "g", "a", "b", "h"]))) -- Eval (SplitOn (Eval (FromList '["a", "b"])) (Eval (FromList '[ "c", "d", "a", "b", "f", "g", "a", "b", "h"]))) :: [Text] -- = '[ 'Text '["c", "d"], 'Text '["f", "g"], 'Text '["h"]] data SplitOn :: Text -> Text -> Exp [Text] type instance Eval (SplitOn ('Text sep) ('Text txt)) = Eval (F.Map FromList =<< SOLoop sep '( '[], txt)) -- | Helper for SplitOn -- -- >>> :kind! Eval (SOTake '["a", "b"] '[ "c", "d", "a", "b", "f", "g"] '[]) -- Eval (SOTake '["a", "b"] '[ "c", "d", "a", "b", "f", "g"] '[]) :: ([Symbol], -- [Symbol]) -- = '( '["c", "d"], '["f", "g"]) data SOTake :: [Symbol] -> [Symbol] -> [Symbol] -> Exp ([Symbol], [Symbol]) type instance Eval (SOTake sep '[] accum) = '(accum, '[]) type instance Eval (SOTake sep (t ': txt) accum) = Eval (If (Eval (F.IsPrefixOf sep (t ': txt))) (Pure '(accum, Eval (F.Drop (Eval (F.Length sep)) (t ': txt)))) (SOTake sep txt (Eval (accum ++ '[t]))) ) -- | Helper for SplitOn data SOLoop :: [Symbol] -> ([[Symbol]],[Symbol]) -> Exp [[Symbol]] type instance Eval (SOLoop sep '(acc, '[])) = acc type instance Eval (SOLoop sep '(acc, (t ': txt))) = Eval (SOLoop sep =<< First (F.Snoc acc) =<< SOTake sep (t ': txt) '[]) -- | Split for type-level text. -- -- === __Example__ -- -- >>> :kind! Eval (Split S.IsSpace (Eval (FromList '[ "c", "d", " ", "b", "f", " ", "a", "b", "h"]))) -- Eval (Split S.IsSpace (Eval (FromList '[ "c", "d", " ", "b", "f", " ", "a", "b", "h"]))) :: [Text] -- = '[ 'Text '["c", "d"], 'Text '["b", "f"], 'Text '["a", "b", "h"]] data Split :: (Symbol -> Exp Bool) -> Text -> Exp [Text] type instance Eval (Split p ('Text txt)) = Eval (F.Map FromList =<< SplitLoop p '( '[], txt)) -- | Helper for Split data SplitTake :: (Symbol -> Exp Bool) -> [Symbol] -> [Symbol] -> Exp ([Symbol], [Symbol]) type instance Eval (SplitTake p '[] accum) = '(accum, '[]) type instance Eval (SplitTake p (t ': txt) accum) = Eval (If (Eval (p t)) (Pure '(accum, txt)) (SplitTake p txt (Eval (accum ++ '[t]))) ) -- | Helper for Split data SplitLoop :: (Symbol -> Exp Bool) -> ([[Symbol]],[Symbol]) -> Exp [[Symbol]] type instance Eval (SplitLoop p '(acc, '[])) = acc type instance Eval (SplitLoop p '(acc, (t ': txt))) = Eval (SplitLoop p =<< First (F.Snoc acc) =<< SplitTake p (t ': txt) '[]) -- | Lines for type-level text. -- -- === __Example__ -- -- >>> :kind! Eval (Lines =<< FromList '[ "o", "k", "\n", "h", "m", "m ", "\n", "a", "b"]) -- Eval (Lines =<< FromList '[ "o", "k", "\n", "h", "m", "m ", "\n", "a", "b"]) :: [Text] -- = '[ 'Text '["o", "k"], 'Text '["h", "m", "m "], 'Text '["a", "b"]] data Lines :: Text -> Exp [Text] type instance Eval (Lines txt) = Eval (Split S.IsNewLine txt) -- | Words for type-level text. -- -- === __Example__ -- -- >>> :kind! Eval (Words =<< FromList '[ "o", "k", " ", "h", "m", "m ", "\n", "a", "b"]) -- Eval (Words =<< FromList '[ "o", "k", " ", "h", "m", "m ", "\n", "a", "b"]) :: [Text] -- = '[ 'Text '["o", "k"], 'Text '["h", "m", "m "], 'Text '["a", "b"]] data Words :: Text -> Exp [Text] type instance Eval (Words txt) = Eval (Split S.IsSpaceDelim txt) -- | Unlines for type-level text. This adds a newline to each Text and then -- concats them. -- -- === __Example__ -- -- >>> :kind! Eval (Unlines '[ 'Text '["o", "k"], 'Text '["h", "m", "m "], 'Text '["a", "b"]]) -- Eval (Unlines '[ 'Text '["o", "k"], 'Text '["h", "m", "m "], 'Text '["a", "b"]]) :: Text -- = 'Text '["o", "k", "\n", "h", "m", "m ", "\n", "a", "b", "\n"] data Unlines :: [Text] -> Exp Text type instance Eval (Unlines txts) = Eval (Concat =<< F.Map (Flip Append (Singleton @@ "\n")) txts) -- | Unwords for type-level text. This uses 'Intercalate' to add space-symbol -- between the given texts. -- -- === __Example__ -- -- >>> :kind! Eval (Unwords '[ 'Text '["o", "k"], 'Text '["h", "m", "m "], 'Text '["a", "b"]]) -- Eval (Unwords '[ 'Text '["o", "k"], 'Text '["h", "m", "m "], 'Text '["a", "b"]]) :: Text -- = 'Text '["o", "k", " ", "h", "m", "m ", " ", "a", "b"] data Unwords :: [Text] -> Exp Text type instance Eval (Unwords txts) = Eval (Intercalate ('Text '[" "]) txts) -- | IsPrefixOf for type-level text. -- -- === __Example__ -- -- >>> :kind! Eval (IsPrefixOf ('Text '["a", "a"]) ('Text '["a", "a", "m", "i", "a", "i", "n", "e", "n"])) -- Eval (IsPrefixOf ('Text '["a", "a"]) ('Text '["a", "a", "m", "i", "a", "i", "n", "e", "n"])) :: Bool -- = 'True data IsPrefixOf :: Text -> Text -> Exp Bool type instance Eval (IsPrefixOf ('Text l1) ('Text l2) ) = Eval (F.IsPrefixOf l1 l2) -- | IsSuffixOf for type-level text. -- -- === __Example__ -- -- >>> :kind! Eval (IsSuffixOf ('Text '["n", "e", "n"]) ('Text '["a", "a", "m", "i", "a", "i", "n", "e", "n"])) -- Eval (IsSuffixOf ('Text '["n", "e", "n"]) ('Text '["a", "a", "m", "i", "a", "i", "n", "e", "n"])) :: Bool -- = 'True data IsSuffixOf :: Text -> Text -> Exp Bool type instance Eval (IsSuffixOf ('Text l1) ('Text l2) ) = Eval (F.IsSuffixOf l1 l2) -- | IsInfixOf for type-level text. -- -- === __Example__ -- -- >>> :kind! Eval (IsInfixOf ('Text '["m", "i", "a"]) ('Text '["a", "a", "m", "i", "a", "i", "n", "e", "n"])) -- Eval (IsInfixOf ('Text '["m", "i", "a"]) ('Text '["a", "a", "m", "i", "a", "i", "n", "e", "n"])) :: Bool -- = 'True data IsInfixOf :: Text -> Text -> Exp Bool type instance Eval (IsInfixOf ('Text l1) ('Text l2) ) = Eval (F.IsInfixOf l1 l2)