ascii-superset 1.3.0.0 → 1.3.0.1
raw patch · 12 files changed
+920/−785 lines, 12 filesdep ~basedep ~hspecPVP: major bump suggested
API removals or changes: PVP suggests a major version bump
Dependency ranges changed: base, hspec
API changes (from Hackage documentation)
- ASCII.CaseRefinement: data ASCII'case (letterCase :: Case) superset
+ ASCII.CaseRefinement: data ASCII'case (letterCase :: Case) (superset :: Type)
- ASCII.Isomorphism: class CharSuperset char => CharIso char
+ ASCII.Isomorphism: class CharSuperset (char :: Type) => CharIso char
- ASCII.Isomorphism: class StringSuperset string => StringIso string
+ ASCII.Isomorphism: class StringSuperset string => StringIso (string :: Type)
- ASCII.Refinement: data ASCII superset
+ ASCII.Refinement: data ASCII (superset :: Type)
- ASCII.Superset: class (ToChar char, FromChar char) => CharSuperset char
+ ASCII.Superset: class (ToChar char, FromChar char) => CharSuperset (char :: Type)
- ASCII.Superset: class FromChar char
+ ASCII.Superset: class FromChar (char :: Type)
- ASCII.Superset: class FromString string
+ ASCII.Superset: class FromString (string :: Type)
- ASCII.Superset: class (ToString string, FromString string) => StringSuperset string
+ ASCII.Superset: class (ToString string, FromString string) => StringSuperset (string :: Type)
- ASCII.Superset: class ToCasefulChar (letterCase :: Case) char
+ ASCII.Superset: class ToCasefulChar (letterCase :: Case) (char :: Type)
- ASCII.Superset: class ToCasefulString (letterCase :: Case) string
+ ASCII.Superset: class ToCasefulString (letterCase :: Case) (string :: Type)
- ASCII.Superset: class ToCaselessChar char
+ ASCII.Superset: class ToCaselessChar (char :: Type)
- ASCII.Superset: class ToCaselessString string
+ ASCII.Superset: class ToCaselessString (string :: Type)
- ASCII.Superset: class ToCaselessChar char => ToChar char
+ ASCII.Superset: class ToCaselessChar char => ToChar (char :: Type)
- ASCII.Superset: class ToCaselessString string => ToString string
+ ASCII.Superset: class ToCaselessString string => ToString (string :: Type)
- ASCII.Superset.Text: class ToText a
+ ASCII.Superset.Text: class ToText (a :: Type)
- ASCII.SupersetConversion: class (StringSuperset a, StringSuperset b) => StringSupersetConversion a b
+ ASCII.SupersetConversion: class (StringSuperset a, StringSuperset b) => StringSupersetConversion (a :: Type) (b :: Type)
Files
- ascii-superset.cabal +4/−4
- changelog.md +4/−0
- library/ASCII/CaseRefinement.hs +227/−149
- library/ASCII/Isomorphism.hs +9/−8
- library/ASCII/Refinement.hs +19/−5
- library/ASCII/Refinement/Internal.hs +80/−79
- library/ASCII/Refinement/Internal.hs-boot +6/−4
- library/ASCII/Superset.hs +338/−307
- library/ASCII/Superset/Text.hs +39/−39
- library/ASCII/SupersetConversion.hs +38/−34
- library/ASCII/SupersetConversion.hs-boot +4/−1
- test/Main.hs +152/−155
ascii-superset.cabal view
@@ -1,7 +1,7 @@ cabal-version: 3.0 name: ascii-superset-version: 1.3.0.0+version: 1.3.0.1 synopsis: Representing ASCII with refined supersets category: Data, Text @@ -26,7 +26,7 @@ location: git://github.com/typeclasses/ascii-superset.git common base- default-language: Haskell2010+ default-language: GHC2021 ghc-options: -Wall default-extensions:@@ -45,7 +45,7 @@ , ascii-case ^>= 1.0.1 , ascii-caseless ^>= 0.0.0 , ascii-char ^>= 1.0- , base ^>= 4.14 || ^>= 4.15 || ^>= 4.16 || ^>= 4.17+ , base ^>= 4.16 || ^>= 4.17 || ^>= 4.18 , text ^>= 1.2.4 || ^>= 2.0 library@@ -87,4 +87,4 @@ build-depends: , ascii-superset- , hspec ^>= 2.8.5 || ^>= 2.9 || ^>= 2.10+ , hspec ^>= 2.9.7 || ^>= 2.10 || ^>= 2.11
changelog.md view
@@ -1,3 +1,7 @@+### 1.3.0.1 (2023-06-26)++Raised language version to GHC2021.+ ### 1.3.0.0 (2023-02-28) Removed the `ASCII.Lift` module. The `Lift` class is now gone. It was a mess. It
library/ASCII/CaseRefinement.hs view
@@ -1,116 +1,143 @@ module ASCII.CaseRefinement- (- {- * ASCII'case type constructor -} ASCII'case, lift, asciiCaseUnsafe, forgetCase,- {- ** Aliases -} {- $aliases -} ASCII'upper, ASCII'lower,- {- * Character functions -} validateChar, fromCaselessChar,- toCaselessChar, substituteChar, asCaselessChar, refineCharToCase,- {- * String functions -} validateString, fromCaselessCharList,- toCaselessCharList, substituteString, mapChars, refineStringToCase,- {- * KnownCase -} KnownCase (..),+ ( -- * ASCII'case type constructor+ ASCII'case,+ lift,+ asciiCaseUnsafe,+ forgetCase,++ -- ** Aliases+ -- $aliases+ ASCII'upper,+ ASCII'lower,++ -- * Character functions+ validateChar,+ fromCaselessChar,+ toCaselessChar,+ substituteChar,+ asCaselessChar,+ refineCharToCase,++ -- * String functions+ validateString,+ fromCaselessCharList,+ toCaselessCharList,+ substituteString,+ mapChars,+ refineStringToCase,++ -- * KnownCase+ KnownCase (..), )- where+where import ASCII.Case (Case (..))+import ASCII.Case qualified as Case import ASCII.Caseless (CaselessChar)-import {-# source #-} ASCII.Refinement.Internal (ASCII)+import ASCII.Caseless qualified as Caseless+import ASCII.Char qualified as ASCII+import {-# SOURCE #-} ASCII.Refinement.Internal (ASCII)+import {-# SOURCE #-} ASCII.Refinement.Internal qualified as Refinement import ASCII.Superset (CharSuperset, StringSuperset)--import qualified ASCII.Case as Case-import qualified ASCII.Caseless as Caseless-import qualified ASCII.Char as ASCII-import qualified ASCII.Superset as S-import {-# source #-} qualified ASCII.Refinement.Internal as Refinement-+import ASCII.Superset qualified as S import Control.Monad (guard)+import Data.Bool qualified as Bool import Data.Data (Data, Typeable) import Data.Eq (Eq) import Data.Foldable (any) import Data.Function (($), (.)) import Data.Hashable (Hashable)+import Data.Kind (Type)+import Data.List qualified as List import Data.Maybe (Maybe (..)) import Data.Monoid (Monoid) import Data.Ord (Ord, (>)) import Data.Semigroup (Semigroup) import GHC.Generics (Generic)-import Prelude (succ) import Text.Show (Show, showList, showParen, showString, showsPrec)--import qualified Data.Bool as Bool-import qualified Data.List as List--{-| Indicates that a value from some ASCII superset is valid ASCII, and also- that any letters belong to a particular 'Case' indicated by the @letterCase@- type parameter--The @superset@ type parameter is the ASCII superset, which should be a type with-an instance of either 'CharSuperset' or 'StringSuperset'.+import Prelude (succ) -For example, whereas a 'Data.Text.Text' value may contain a combination of ASCII-and non-ASCII characters, a value of type @'ASCII'case' ''ASCII.Case.UpperCase'-'Data.Text.Text'@ may contain only uppercase ASCII letters and ASCII-non-letters. -}-newtype ASCII'case (letterCase :: Case) superset = ASCII'case_Unsafe- { lift :: superset- {- ^ Discard the evidence that the value is known to consist- entirely of ASCII characters in a particular case -}+-- | Indicates that a value from some ASCII superset is valid ASCII, and also+-- that any letters belong to a particular 'Case' indicated by the @letterCase@+-- type parameter+--+-- The @superset@ type parameter is the ASCII superset, which should be a type with+-- an instance of either 'CharSuperset' or 'StringSuperset'.+--+-- For example, whereas a 'Data.Text.Text' value may contain a combination of ASCII+-- and non-ASCII characters, a value of type @'ASCII'case' ''ASCII.Case.UpperCase'+-- 'Data.Text.Text'@ may contain only uppercase ASCII letters and ASCII+-- non-letters.+newtype ASCII'case (letterCase :: Case) (superset :: Type) = ASCII'case_Unsafe+ { -- | Discard the evidence that the value is known to consist+ -- entirely of ASCII characters in a particular case+ lift :: superset } -deriving stock instance Eq superset =>- Eq (ASCII'case letterCase superset)+deriving stock instance+ Eq superset =>+ Eq (ASCII'case letterCase superset) -deriving stock instance Ord superset =>- Ord (ASCII'case letterCase superset)+deriving stock instance+ Ord superset =>+ Ord (ASCII'case letterCase superset) -deriving newtype instance Hashable superset =>- Hashable (ASCII'case letterCase superset)+deriving newtype instance+ Hashable superset =>+ Hashable (ASCII'case letterCase superset) -deriving newtype instance Semigroup superset =>- Semigroup (ASCII'case letterCase superset)+deriving newtype instance+ Semigroup superset =>+ Semigroup (ASCII'case letterCase superset) -deriving newtype instance Monoid superset =>- Monoid (ASCII'case letterCase superset)+deriving newtype instance+ Monoid superset =>+ Monoid (ASCII'case letterCase superset) -deriving stock instance (Data superset, Typeable letterCase) =>- Data (ASCII'case letterCase superset)+deriving stock instance+ (Data superset, Typeable letterCase) =>+ Data (ASCII'case letterCase superset) deriving stock instance Generic (ASCII'case letterCase superset) instance Show superset => Show (ASCII'case letterCase superset) where- showsPrec d x = showParen (d > app_prec) $- showString "asciiCaseUnsafe " . showsPrec (succ app_prec) (lift x)- where app_prec = 10+ showsPrec d x =+ showParen (d > app_prec) $+ showString "asciiCaseUnsafe " . showsPrec (succ app_prec) (lift x)+ where+ app_prec = 10 - showList x = showString "asciiCaseUnsafe " . showList (List.map lift x)+ showList x = showString "asciiCaseUnsafe " . showList (List.map lift x) instance S.ToCaselessChar char => S.ToCaselessChar (ASCII'case letterCase char) where- isAsciiCaselessChar _ = Bool.True- toCaselessCharUnsafe = S.toCaselessCharUnsafe . lift+ isAsciiCaselessChar _ = Bool.True+ toCaselessCharUnsafe = S.toCaselessCharUnsafe . lift instance S.CharSuperset char => S.ToChar (ASCII'case letterCase char) where- isAsciiChar _ = Bool.True- toCharUnsafe = S.toCharUnsafe . lift+ isAsciiChar _ = Bool.True+ toCharUnsafe = S.toCharUnsafe . lift instance S.ToCaselessString string => S.ToCaselessString (ASCII'case letterCase string) where- isAsciiCaselessString _ = Bool.True- toCaselessCharListUnsafe = S.toCaselessCharListUnsafe . lift- toCaselessCharListSub = S.toCaselessCharListSub . lift+ isAsciiCaselessString _ = Bool.True+ toCaselessCharListUnsafe = S.toCaselessCharListUnsafe . lift+ toCaselessCharListSub = S.toCaselessCharListSub . lift instance S.ToString string => S.ToString (ASCII'case letterCase string) where- isAsciiString _ = Bool.True- toCharListUnsafe = S.toCharListUnsafe . lift- toCharListSub = S.toCharListUnsafe . lift+ isAsciiString _ = Bool.True+ toCharListUnsafe = S.toCharListUnsafe . lift+ toCharListSub = S.toCharListUnsafe . lift instance (S.FromChar superset, KnownCase letterCase) => S.ToCasefulChar letterCase (ASCII'case letterCase superset) where- toCasefulChar = asciiCaseUnsafe . S.fromChar . Caseless.toCase (theCase @letterCase)+ toCasefulChar = asciiCaseUnsafe . S.fromChar . Caseless.toCase (theCase @letterCase) instance (S.FromString superset, KnownCase letterCase) => S.ToCasefulString letterCase (ASCII'case letterCase superset) where- toCasefulString = asciiCaseUnsafe . S.fromCharList . List.map (Caseless.toCase (theCase @letterCase))--{-| Change the type of an ASCII superset value that is known to be valid ASCII where- letters are restricted to the 'Case' designated by the @letterCase@ type variable+ toCasefulString = asciiCaseUnsafe . S.fromCharList . List.map (Caseless.toCase (theCase @letterCase)) -This is "unsafe" because this assertion is unchecked, so this function is capable-of producing an invalid 'ASCII'case' value. -}+-- | Change the type of an ASCII superset value that is known to be valid ASCII where+-- letters are restricted to the 'Case' designated by the @letterCase@ type variable+--+-- This is "unsafe" because this assertion is unchecked, so this function is capable+-- of producing an invalid 'ASCII'case' value. asciiCaseUnsafe :: superset -> ASCII'case letterCase superset asciiCaseUnsafe = ASCII'case_Unsafe @@ -119,10 +146,11 @@ --- -{- $aliases+-- $aliases+--+-- The 'ASCII'upper' and 'ASCII'lower' type aliases exist primarily so that you can+-- use 'ASCII'case' without the DataKinds language extension. -The 'ASCII'upper' and 'ASCII'lower' type aliases exist primarily so that you can-use 'ASCII'case' without the DataKinds language extension. -} type ASCII'upper superset = ASCII'case 'UpperCase superset type ASCII'lower superset = ASCII'case 'LowerCase superset@@ -130,115 +158,165 @@ --- class KnownCase (letterCase :: Case) where theCase :: Case+ instance KnownCase 'UpperCase where theCase = UpperCase+ instance KnownCase 'LowerCase where theCase = LowerCase --- -{-| Return 'Just' an 'ASCII'case' character if the input is an ASCII character- in the proper case, or 'Nothing' otherwise -}-validateChar :: forall letterCase superset. KnownCase letterCase => CharSuperset superset =>- superset {- ^ Character which may or may not be in the ASCII character set;- if a letter, may be in any case -}- -> Maybe (ASCII'case letterCase superset)+-- | Return 'Just' an 'ASCII'case' character if the input is an ASCII character+-- in the proper case, or 'Nothing' otherwise+validateChar ::+ forall letterCase superset.+ KnownCase letterCase =>+ CharSuperset superset =>+ -- | Character which may or may not be in the ASCII character set;+ -- if a letter, may be in any case+ superset ->+ Maybe (ASCII'case letterCase superset) validateChar x = do- c <- S.toCharMaybe x- guard (Bool.not (Case.isCase (Case.opposite (theCase @letterCase)) c))- Just (asciiCaseUnsafe x)+ c <- S.toCharMaybe x+ guard (Bool.not (Case.isCase (Case.opposite (theCase @letterCase)) c))+ Just (asciiCaseUnsafe x) -{-| Return an 'ASCII'case' character if the input is an ASCII character in the- proper case, or 'ASCII.Substitute' otherwise -}-substituteChar :: forall letterCase superset. KnownCase letterCase => CharSuperset superset =>- superset- -> ASCII'case letterCase superset+-- | Return an 'ASCII'case' character if the input is an ASCII character in the+-- proper case, or 'ASCII.Substitute' otherwise+substituteChar ::+ forall letterCase superset.+ KnownCase letterCase =>+ CharSuperset superset =>+ superset ->+ ASCII'case letterCase superset substituteChar x = case validateChar x of- Nothing -> asciiCaseUnsafe (S.fromChar ASCII.Substitute)- Just c -> c+ Nothing -> asciiCaseUnsafe (S.fromChar ASCII.Substitute)+ Just c -> c -{-| Lift a 'CaselessChar' into a superset type, wrapped in the 'ASCII'case'- refinement to save the evidence that it is ASCII in a particular case -}-fromCaselessChar :: forall letterCase superset. KnownCase letterCase => CharSuperset superset =>- CaselessChar -- ^ Character which, if it is a letter, does not have a specified case- -> ASCII'case letterCase superset+-- | Lift a 'CaselessChar' into a superset type, wrapped in the 'ASCII'case'+-- refinement to save the evidence that it is ASCII in a particular case+fromCaselessChar ::+ forall letterCase superset.+ KnownCase letterCase =>+ CharSuperset superset =>+ -- | Character which, if it is a letter, does not have a specified case+ CaselessChar ->+ ASCII'case letterCase superset fromCaselessChar = asciiCaseUnsafe . S.fromChar . Caseless.toCase (theCase @letterCase) -{-| Given a character from some type that is known to represent an ASCII- character in a particular case, obtain the caseless ASCII character- it represents -}-toCaselessChar :: CharSuperset superset =>- ASCII'case letterCase superset {- ^ Character that is known to be ASCII, and- in the particular case if it is a letter -}- -> CaselessChar+-- | Given a character from some type that is known to represent an ASCII+-- character in a particular case, obtain the caseless ASCII character+-- it represents+toCaselessChar ::+ CharSuperset superset =>+ -- | Character that is known to be ASCII, and+ -- in the particular case if it is a letter+ ASCII'case letterCase superset ->+ CaselessChar toCaselessChar = Caseless.disregardCase . S.toCharUnsafe . lift -{-| Given a character from a larger set that is known to represent an ASCII- character, manipulate it as if it were an ASCII character -}-asCaselessChar :: forall letterCase superset. KnownCase letterCase => CharSuperset superset =>- (CaselessChar -> CaselessChar) -- ^ Case-insensitive function over ASCII characters- -> ASCII'case letterCase superset {- ^ Character that is known to be ASCII, and- in the particular case if it is a letter -}- -> ASCII'case letterCase superset+-- | Given a character from a larger set that is known to represent an ASCII+-- character, manipulate it as if it were an ASCII character+asCaselessChar ::+ forall letterCase superset.+ KnownCase letterCase =>+ CharSuperset superset =>+ -- | Case-insensitive function over ASCII characters+ (CaselessChar -> CaselessChar) ->+ -- | Character that is known to be ASCII, and+ -- in the particular case if it is a letter+ ASCII'case letterCase superset ->+ ASCII'case letterCase superset asCaselessChar f = asciiCaseUnsafe . S.asCharUnsafe g . lift where g = Caseless.toCase (theCase @letterCase) . f . Caseless.assumeCaseUnsafe (theCase @letterCase) -{-| Given an ASCII superset character that is known to be valid ASCII,- refine it further by converting it to a particular letter case -}-refineCharToCase :: forall letterCase char. KnownCase letterCase => CharSuperset char =>- ASCII char -> ASCII'case letterCase char+-- | Given an ASCII superset character that is known to be valid ASCII,+-- refine it further by converting it to a particular letter case+refineCharToCase ::+ forall letterCase char.+ KnownCase letterCase =>+ CharSuperset char =>+ ASCII char ->+ ASCII'case letterCase char refineCharToCase = asciiCaseUnsafe . S.toCaseChar (theCase @letterCase) . Refinement.lift --- -{-| Return 'Just' an 'ASCII'case' string if the input consists entirely of ASCII- characters in the proper case, or 'Nothing' otherwise -}-validateString :: forall letterCase superset. KnownCase letterCase => StringSuperset superset =>- superset -- ^ String which may or may not be valid ASCII, where letters may be in any case- -> Maybe (ASCII'case letterCase superset)+-- | Return 'Just' an 'ASCII'case' string if the input consists entirely of ASCII+-- characters in the proper case, or 'Nothing' otherwise+validateString ::+ forall letterCase superset.+ KnownCase letterCase =>+ StringSuperset superset =>+ -- | String which may or may not be valid ASCII, where letters may be in any case+ superset ->+ Maybe (ASCII'case letterCase superset) validateString x = do- s <- S.toCharListMaybe x- guard (Bool.not (any (Case.isCase (Case.opposite (theCase @letterCase))) s))- Just (asciiCaseUnsafe x)+ s <- S.toCharListMaybe x+ guard (Bool.not (any (Case.isCase (Case.opposite (theCase @letterCase))) s))+ Just (asciiCaseUnsafe x) -{-| Lift a list of 'CaselessChar' into a superset string type, wrapped in the- 'ASCII'case' refinement to save the evidence that all of the characters in- the string are ASCII in a particular case -}-fromCaselessCharList :: forall letterCase superset. KnownCase letterCase => StringSuperset superset =>- [CaselessChar] -- ^ Case-insensitive ASCII string represented as a list of caseless characters- -> ASCII'case letterCase superset+-- | Lift a list of 'CaselessChar' into a superset string type, wrapped in the+-- 'ASCII'case' refinement to save the evidence that all of the characters in+-- the string are ASCII in a particular case+fromCaselessCharList ::+ forall letterCase superset.+ KnownCase letterCase =>+ StringSuperset superset =>+ -- | Case-insensitive ASCII string represented as a list of caseless characters+ [CaselessChar] ->+ ASCII'case letterCase superset fromCaselessCharList = asciiCaseUnsafe . S.fromCharList . List.map (Caseless.toCase (theCase @letterCase)) -{-| Given a string from some type that is known to represent only ASCII characters- in a particular case, obtain the caseless characters it represents -}-toCaselessCharList :: forall letterCase superset. KnownCase letterCase => StringSuperset superset =>- ASCII'case letterCase superset -- ^ String that is known to be valid ASCII in a particular case- -> [CaselessChar]+-- | Given a string from some type that is known to represent only ASCII characters+-- in a particular case, obtain the caseless characters it represents+toCaselessCharList ::+ forall letterCase superset.+ KnownCase letterCase =>+ StringSuperset superset =>+ -- | String that is known to be valid ASCII in a particular case+ ASCII'case letterCase superset ->+ [CaselessChar] toCaselessCharList = List.map (Caseless.assumeCaseUnsafe (theCase @letterCase)) . S.toCharListUnsafe . lift -{-| Forces a string from a larger character set into cased ASCII by using the- 'ASCII.Substitute' character in place of any unacceptable characters -}-substituteString :: forall letterCase superset. KnownCase letterCase => StringSuperset superset =>- superset -- ^ String which may or may not be valid ASCII, where letters may be in any case- -> ASCII'case letterCase superset+-- | Forces a string from a larger character set into cased ASCII by using the+-- 'ASCII.Substitute' character in place of any unacceptable characters+substituteString ::+ forall letterCase superset.+ KnownCase letterCase =>+ StringSuperset superset =>+ -- | String which may or may not be valid ASCII, where letters may be in any case+ superset ->+ ASCII'case letterCase superset substituteString = asciiCaseUnsafe . S.fromCharList . List.map f . S.toCharListSub where- f x = if Case.isCase (Case.opposite (theCase @letterCase)) x- then ASCII.Substitute- else x+ f x =+ if Case.isCase (Case.opposite (theCase @letterCase)) x+ then ASCII.Substitute+ else x -{-| Given a string from a larger set that is known to consist entirely of ASCII- characters in a particular case, map over the characters in the string as if- they were caseless ASCII characters -}-mapChars :: forall letterCase superset. KnownCase letterCase => StringSuperset superset =>- (CaselessChar -> CaselessChar) -- ^ Case-insensitive function over ASCII characters- -> ASCII'case letterCase superset -- ^ String that is known to be valid ASCII in a particular case- -> ASCII'case letterCase superset+-- | Given a string from a larger set that is known to consist entirely of ASCII+-- characters in a particular case, map over the characters in the string as if+-- they were caseless ASCII characters+mapChars ::+ forall letterCase superset.+ KnownCase letterCase =>+ StringSuperset superset =>+ -- | Case-insensitive function over ASCII characters+ (CaselessChar -> CaselessChar) ->+ -- | String that is known to be valid ASCII in a particular case+ ASCII'case letterCase superset ->+ ASCII'case letterCase superset mapChars f = asciiCaseUnsafe . S.mapCharsUnsafe g . lift where g = Caseless.toCase (theCase @letterCase) . f . Caseless.assumeCaseUnsafe (theCase @letterCase) -{-| Given an ASCII superset string that is known to be valid ASCII,-refine it further by converting it to a particular letter case -}-refineStringToCase :: forall letterCase char. KnownCase letterCase => StringSuperset char =>- ASCII char -> ASCII'case letterCase char+-- | Given an ASCII superset string that is known to be valid ASCII,+-- refine it further by converting it to a particular letter case+refineStringToCase ::+ forall letterCase char.+ KnownCase letterCase =>+ StringSuperset char =>+ ASCII char ->+ ASCII'case letterCase char refineStringToCase = asciiCaseUnsafe . S.toCaseString (theCase @letterCase) . Refinement.lift
library/ASCII/Isomorphism.hs view
@@ -3,22 +3,23 @@ import ASCII.Char (Char) import ASCII.Superset (CharSuperset, StringSuperset, fromChar) import Data.Function (id, (.))+import Data.Kind (Type) import Data.List (map) -class CharSuperset char => CharIso char where- toChar :: char -> Char+class CharSuperset (char :: Type) => CharIso char where+ toChar :: char -> Char asChar :: CharIso char => (Char -> Char) -> char -> char asChar f = fromChar . f . toChar -class StringSuperset string => StringIso string where- toCharList :: string -> [Char]- mapChars :: (Char -> Char) -> string -> string+class StringSuperset string => StringIso (string :: Type) where+ toCharList :: string -> [Char]+ mapChars :: (Char -> Char) -> string -> string -- | 'Char' is trivially isomorphic to itself. (This instance is uninteresting.) instance CharIso Char where- toChar = id+ toChar = id instance CharIso char => StringIso [char] where- toCharList = map toChar- mapChars f = map (asChar f)+ toCharList = map toChar+ mapChars f = map (asChar f)
library/ASCII/Refinement.hs view
@@ -1,9 +1,23 @@ module ASCII.Refinement- (- {- * ASCII type constructor -} ASCII, lift, asciiUnsafe,- {- * Character functions -} validateChar, fromChar, toChar, substituteChar, asChar,- {- * String functions -} validateString, fromCharList, toCharList, substituteString, mapChars,+ ( -- * ASCII type constructor+ ASCII,+ lift,+ asciiUnsafe,++ -- * Character functions+ validateChar,+ fromChar,+ toChar,+ substituteChar,+ asChar,++ -- * String functions+ validateString,+ fromCharList,+ toCharList,+ substituteString,+ mapChars, )- where+where import ASCII.Refinement.Internal
library/ASCII/Refinement/Internal.hs view
@@ -1,36 +1,35 @@ module ASCII.Refinement.Internal where -import qualified ASCII.Char as ASCII-import qualified ASCII.Isomorphism as I-import qualified ASCII.Superset as S--import {-# source #-} ASCII.SupersetConversion (StringSupersetConversion)+import ASCII.Char qualified as ASCII+import ASCII.Isomorphism qualified as I+import ASCII.Superset qualified as S+import {-# SOURCE #-} ASCII.SupersetConversion (StringSupersetConversion)+import {-# SOURCE #-} ASCII.SupersetConversion qualified as SupersetConversion+import Data.Bool qualified as Bool import Data.Data (Data) import Data.Eq (Eq) import Data.Function (id, ($), (.)) import Data.Hashable (Hashable)+import Data.Kind (Type) import Data.List (map) import Data.Maybe (Maybe (..)) import Data.Monoid (Monoid) import Data.Ord (Ord, (>)) import Data.Semigroup (Semigroup) import GHC.Generics (Generic)+import Text.Show qualified as Show import Prelude (succ) -import qualified Data.Bool as Bool-import qualified Text.Show as Show-import {-# source #-} qualified ASCII.SupersetConversion as SupersetConversion--{-| This type constructor indicates that a value from some ASCII superset- is valid ASCII--The type parameter is the ASCII superset, which should be a type with an-instance of either 'CharSuperset' or 'StringSuperset'.--For example, whereas a 'Data.Text.Text' value may contain a combination of ASCII-and non-ASCII characters, a value of type @'ASCII' 'Data.Text.Text'@ may contain-only ASCII characters. -}-newtype ASCII superset = ASCII_Unsafe { lift :: superset }+-- | This type constructor indicates that a value from some ASCII superset+-- is valid ASCII+--+-- The type parameter is the ASCII superset, which should be a type with an+-- instance of either 'CharSuperset' or 'StringSuperset'.+--+-- For example, whereas a 'Data.Text.Text' value may contain a combination of ASCII+-- and non-ASCII characters, a value of type @'ASCII' 'Data.Text.Text'@ may contain+-- only ASCII characters.+newtype ASCII (superset :: Type) = ASCII_Unsafe {lift :: superset} deriving stock instance Eq superset => Eq (ASCII superset) @@ -47,63 +46,65 @@ deriving stock instance Generic (ASCII superset) instance Show.Show superset => Show.Show (ASCII superset) where- showsPrec d x = Show.showParen (d > app_prec) $- Show.showString "asciiUnsafe " . Show.showsPrec (succ app_prec) (lift x)- where app_prec = 10+ showsPrec d x =+ Show.showParen (d > app_prec) $+ Show.showString "asciiUnsafe " . Show.showsPrec (succ app_prec) (lift x)+ where+ app_prec = 10 - showList x = Show.showString "asciiUnsafe " . Show.showList (map lift x)+ showList x = Show.showString "asciiUnsafe " . Show.showList (map lift x) instance S.ToCaselessChar char => S.ToCaselessChar (ASCII char) where- isAsciiCaselessChar _ = Bool.True- toCaselessCharUnsafe = S.toCaselessCharUnsafe . lift+ isAsciiCaselessChar _ = Bool.True+ toCaselessCharUnsafe = S.toCaselessCharUnsafe . lift instance S.CharSuperset char => S.ToChar (ASCII char) where- isAsciiChar _ = Bool.True- toCharUnsafe = S.toCharUnsafe . lift+ isAsciiChar _ = Bool.True+ toCharUnsafe = S.toCharUnsafe . lift instance S.CharSuperset char => S.FromChar (ASCII char) where- fromChar = asciiUnsafe . S.fromChar+ fromChar = asciiUnsafe . S.fromChar instance S.CharSuperset char => S.CharSuperset (ASCII char) where- toCaseChar c = asciiUnsafe . S.toCaseChar c . lift+ toCaseChar c = asciiUnsafe . S.toCaseChar c . lift instance S.CharSuperset char => I.CharIso (ASCII char) where- toChar = S.toCharUnsafe+ toChar = S.toCharUnsafe instance S.ToCaselessString string => S.ToCaselessString (ASCII string) where- isAsciiCaselessString _ = Bool.True- toCaselessCharListUnsafe = S.toCaselessCharListUnsafe . lift- toCaselessCharListSub = S.toCaselessCharListSub . lift+ isAsciiCaselessString _ = Bool.True+ toCaselessCharListUnsafe = S.toCaselessCharListUnsafe . lift+ toCaselessCharListSub = S.toCaselessCharListSub . lift instance S.ToString string => S.ToString (ASCII string) where- isAsciiString _ = Bool.True- toCharListUnsafe = S.toCharListUnsafe . lift- toCharListSub = S.toCharListUnsafe . lift+ isAsciiString _ = Bool.True+ toCharListUnsafe = S.toCharListUnsafe . lift+ toCharListSub = S.toCharListUnsafe . lift instance S.FromString string => S.FromString (ASCII string) where- fromCharList = asciiUnsafe . S.fromCharList+ fromCharList = asciiUnsafe . S.fromCharList instance S.StringSuperset string => S.StringSuperset (ASCII string) where- substituteString = id- toCaseString c = asciiUnsafe . S.toCaseString c . lift+ substituteString = id+ toCaseString c = asciiUnsafe . S.toCaseString c . lift instance S.StringSuperset string => I.StringIso (ASCII string) where- toCharList = S.toCharListUnsafe- mapChars = S.mapCharsUnsafe--{-| Change the type of an ASCII superset value that is known to be valid ASCII+ toCharList = S.toCharListUnsafe+ mapChars = S.mapCharsUnsafe -This is "unsafe" because this assertion is unchecked, so this function is capable-of producing an invalid 'ASCII' value. -}+-- | Change the type of an ASCII superset value that is known to be valid ASCII+--+-- This is "unsafe" because this assertion is unchecked, so this function is capable+-- of producing an invalid 'ASCII' value. asciiUnsafe :: superset -> ASCII superset asciiUnsafe = ASCII_Unsafe -{-|--@-(map validateChar [-1, 65, 97, 128] :: [Maybe (ASCII Int)])- == [Nothing, Just (asciiUnsafe 65), Just (asciiUnsafe 97), Nothing]-@ -}+-- |+--+-- @+-- (map validateChar [-1, 65, 97, 128] :: [Maybe (ASCII Int)])+-- == [Nothing, Just (asciiUnsafe 65), Just (asciiUnsafe 97), Nothing]+-- @ validateChar :: S.CharSuperset superset => superset -> Maybe (ASCII superset) validateChar x = if S.isAsciiChar x then Just (asciiUnsafe x) else Nothing @@ -116,42 +117,42 @@ toChar :: S.CharSuperset superset => ASCII superset -> ASCII.Char toChar = S.toCharUnsafe . lift -{-|--@-fromCharList [CapitalLetterH, SmallLetterI, ExclamationMark]- == (asciiUnsafe "Hi!" :: ASCII Text)-@ -}+-- |+--+-- @+-- fromCharList [CapitalLetterH, SmallLetterI, ExclamationMark]+-- == (asciiUnsafe "Hi!" :: ASCII Text)+-- @ fromCharList :: S.StringSuperset superset => [ASCII.Char] -> ASCII superset fromCharList = asciiUnsafe . S.fromCharList -{-|--@-toCharList (substituteString \"Piñata" :: ASCII Text) ==- [CapitalLetterP, SmallLetterI, Substitute, SmallLetterA, SmallLetterT, SmallLetterA]-@ -}+-- |+--+-- @+-- toCharList (substituteString \"Piñata" :: ASCII Text) ==+-- [CapitalLetterP, SmallLetterI, Substitute, SmallLetterA, SmallLetterT, SmallLetterA]+-- @ toCharList :: S.StringSuperset superset => ASCII superset -> [ASCII.Char] toCharList = S.toCharListUnsafe . lift -{-| Forces a string from a larger character set into ASCII by using the- 'ASCII.Substitute' character in place of any non-ASCII characters--@-(substituteString \"Cristóbal" :: ASCII Text) == asciiUnsafe "Crist\SUBbal"-@ -}+-- | Forces a string from a larger character set into ASCII by using the+-- 'ASCII.Substitute' character in place of any non-ASCII characters+--+-- @+-- (substituteString \"Cristóbal" :: ASCII Text) == asciiUnsafe "Crist\SUBbal"+-- @ substituteString :: S.StringSuperset superset => superset -> ASCII superset substituteString = asciiUnsafe . S.substituteString -{-|--@-(map validateString [\"Hello", \"Cristóbal"] :: [Maybe (ASCII Text)])- == [Just (asciiUnsafe \"Hello"), Nothing]--(map validateString [\"Hello", \"Cristóbal"] :: [Maybe (ASCII String)])- == [Just (asciiUnsafe \"Hello"), Nothing]-@ -}+-- |+--+-- @+-- (map validateString [\"Hello", \"Cristóbal"] :: [Maybe (ASCII Text)])+-- == [Just (asciiUnsafe \"Hello"), Nothing]+--+-- (map validateString [\"Hello", \"Cristóbal"] :: [Maybe (ASCII String)])+-- == [Just (asciiUnsafe \"Hello"), Nothing]+-- @ validateString :: S.StringSuperset superset => superset -> Maybe (ASCII superset) validateString x = if S.isAsciiString x then Just (asciiUnsafe x) else Nothing @@ -161,6 +162,6 @@ mapChars :: S.StringSuperset superset => (ASCII.Char -> ASCII.Char) -> ASCII superset -> ASCII superset mapChars f = asciiUnsafe . S.mapCharsUnsafe f . lift -{-| For example, this function can convert @ASCII ByteString@ to @ASCII Text@ and vice versa -}+-- | For example, this function can convert @ASCII ByteString@ to @ASCII Text@ and vice versa convertRefinedString :: StringSupersetConversion a b => ASCII a -> ASCII b convertRefinedString (ASCII_Unsafe x) = ASCII_Unsafe (SupersetConversion.convertStringUnsafe x)
library/ASCII/Refinement/Internal.hs-boot view
@@ -1,11 +1,13 @@ module ASCII.Refinement.Internal where import {-# source #-} ASCII.SupersetConversion (StringSupersetConversion)+import Data.Kind (Type) -data ASCII superset+data ASCII (superset :: Type) -lift :: ASCII superset -> superset+lift :: forall (superset :: Type). ASCII superset -> superset -asciiUnsafe :: superset -> ASCII superset+asciiUnsafe :: forall (superset :: Type). superset -> ASCII superset -convertRefinedString :: StringSupersetConversion a b => ASCII a -> ASCII b+convertRefinedString :: StringSupersetConversion (a :: Type) (b :: Type) =>+ ASCII a -> ASCII b
library/ASCII/Superset.hs view
@@ -1,112 +1,132 @@ module ASCII.Superset- (- {- * Characters -}- {- ** Class -} ToCaselessChar (..), ToChar (..), FromChar (..), CharSuperset (..), ToCasefulChar (..),- {- ** Functions -} asCharUnsafe, toCharMaybe, toCaselessCharMaybe, toCharOrFail, toCaselessCharOrFail,- toCharSub, toCaselessCharSub, substituteChar, convertCharMaybe, convertCharOrFail,+ ( -- * Characters - {- * Strings -}- {- ** Class -} ToCaselessString (..), ToString (..), FromString (..), StringSuperset (..), ToCasefulString (..),- {- ** Functions -} toCharListMaybe, toCaselessCharListMaybe, toCharListOrFail, toCaselessCharListOrFail,- convertStringMaybe, convertStringOrFail+ -- ** Class+ ToCaselessChar (..),+ ToChar (..),+ FromChar (..),+ CharSuperset (..),+ ToCasefulChar (..),++ -- ** Functions+ asCharUnsafe,+ toCharMaybe,+ toCaselessCharMaybe,+ toCharOrFail,+ toCaselessCharOrFail,+ toCharSub,+ toCaselessCharSub,+ substituteChar,+ convertCharMaybe,+ convertCharOrFail,++ -- * Strings++ -- ** Class+ ToCaselessString (..),+ ToString (..),+ FromString (..),+ StringSuperset (..),+ ToCasefulString (..),++ -- ** Functions+ toCharListMaybe,+ toCaselessCharListMaybe,+ toCharListOrFail,+ toCaselessCharListOrFail,+ convertStringMaybe,+ convertStringOrFail, )- where+where import ASCII.Case (Case (..))+import ASCII.Case qualified as Case+import {-# SOURCE #-} ASCII.CaseRefinement (KnownCase (..)) import ASCII.Caseless (CaselessChar)-import {-# source #-} ASCII.CaseRefinement (KnownCase (..))+import ASCII.Caseless qualified as Caseless+import ASCII.Char qualified as ASCII import Control.Monad (return) import Control.Monad.Fail (MonadFail (fail)) import Data.Bool (Bool, (&&))+import Data.Bool qualified as Bool+import Data.ByteString qualified as BS+import Data.ByteString.Builder qualified as BSB+import Data.ByteString.Lazy qualified as LBS+import Data.Char qualified as Unicode import Data.Function (id, (.)) import Data.Functor (fmap)+import Data.Int qualified as Int+import Data.Kind (Type)+import Data.List qualified as List import Data.Maybe (Maybe (..)) import Data.Ord ((<=), (>=))+import Data.Text qualified as T+import Data.Text.Lazy qualified as LT+import Data.Text.Lazy.Builder qualified as TB+import Data.Word qualified as Word+import Numeric.Natural qualified as Nat import Prelude ((+), (-))--import qualified ASCII.Case as Case-import qualified ASCII.Caseless as Caseless-import qualified ASCII.Char as ASCII-import qualified Data.Bool as Bool-import qualified Data.ByteString as BS-import qualified Data.ByteString.Builder as BSB-import qualified Data.ByteString.Lazy as LBS-import qualified Data.Char as Unicode-import qualified Data.Int as Int-import qualified Data.List as List-import qualified Data.Text as T-import qualified Data.Text.Lazy as LT-import qualified Data.Text.Lazy.Builder as TB-import qualified Data.Word as Word-import qualified Numeric.Natural as Nat-import qualified Prelude-+import Prelude qualified --- Char --- -{-| Partial conversion to 'CaselessChar'--Generally this will be a superset of the ASCII character set with a 'ToChar'-instance as well, and the conversion will be achieved by discarding the case of-letters. A notable exception is the instance for the 'CaselessChar' type itself,-which is already represented without case and does not have a 'ToChar' instance.--}-class ToCaselessChar char where-- -- | Test whether a character can be converted to 'CaselessChar'- isAsciiCaselessChar :: char -> Bool-- -- | Conversion to 'CaselessChar', defined only where 'isAsciiCaselessChar' is satisfied- toCaselessCharUnsafe :: char -> CaselessChar--{-| Partial conversion to 'ASCII.Char'--This includes the 'ASCII.Char' type itself, character sets that are supersets-of ASCII, and numeric types such as 'Word8' that are often used to represent-ASCII characters.--This does /not/ include 'CaselessChar', because that cannot be converted to-'ASCII.Char' without choosing a case. -}-class ToCaselessChar char => ToChar char where-- -- | Test whether a character can be converted to 'ASCII.Char'- isAsciiChar :: char -> Bool-- -- | Conversion to 'ASCII.Char', defined only where 'isAsciiChar' is satisfied- toCharUnsafe :: char -> ASCII.Char--{-| Total conversion from 'ASCII.Char'--This class includes supersets of ASCII, in which case 'fromChar' is a lifting-function. It also includes 'CaselessChar', in which case 'fromChar' discards-case information.--This does /not/ include 'ASCII.CaseRefinement.ASCII'case', because that represents-a subset of 'ASCII.Char'; not all characters are of the wanted case, so no total-conversion is possible without changing case. -}-class FromChar char where-- -- | Conversion from 'ASCII.Char'- fromChar :: ASCII.Char -> char+-- | Partial conversion to 'CaselessChar'+--+-- Generally this will be a superset of the ASCII character set with a 'ToChar'+-- instance as well, and the conversion will be achieved by discarding the case of+-- letters. A notable exception is the instance for the 'CaselessChar' type itself,+-- which is already represented without case and does not have a 'ToChar' instance.+class ToCaselessChar (char :: Type) where+ -- | Test whether a character can be converted to 'CaselessChar'+ isAsciiCaselessChar :: char -> Bool -{- | Character type with:+ -- | Conversion to 'CaselessChar', defined only where 'isAsciiCaselessChar' is satisfied+ toCaselessCharUnsafe :: char -> CaselessChar -- a total conversion from ASCII; and-- a partial conversion to ASCII -}-class (ToChar char, FromChar char) => CharSuperset char where+-- | Partial conversion to 'ASCII.Char'+--+-- This includes the 'ASCII.Char' type itself, character sets that are supersets+-- of ASCII, and numeric types such as 'Word8' that are often used to represent+-- ASCII characters.+--+-- This does /not/ include 'CaselessChar', because that cannot be converted to+-- 'ASCII.Char' without choosing a case.+class ToCaselessChar char => ToChar (char :: Type) where+ -- | Test whether a character can be converted to 'ASCII.Char'+ isAsciiChar :: char -> Bool - {- | Convert a character in the superset to the designated case,- if it is an ASCII letter of the opposite case. Otherwise, return- the argument unmodified. -}- toCaseChar :: Case -> char -> char+ -- | Conversion to 'ASCII.Char', defined only where 'isAsciiChar' is satisfied+ toCharUnsafe :: char -> ASCII.Char -class ToCasefulChar (letterCase :: Case) char where+-- | Total conversion from 'ASCII.Char'+--+-- This class includes supersets of ASCII, in which case 'fromChar' is a lifting+-- function. It also includes 'CaselessChar', in which case 'fromChar' discards+-- case information.+--+-- This does /not/ include 'ASCII.CaseRefinement.ASCII'case', because that represents+-- a subset of 'ASCII.Char'; not all characters are of the wanted case, so no total+-- conversion is possible without changing case.+class FromChar (char :: Type) where+ -- | Conversion from 'ASCII.Char'+ fromChar :: ASCII.Char -> char - toCasefulChar :: CaselessChar -> char+-- | Character type with:+--+-- - a total conversion from ASCII; and+-- - a partial conversion to ASCII+class (ToChar char, FromChar char) => CharSuperset (char :: Type) where+ -- | Convert a character in the superset to the designated case,+ -- if it is an ASCII letter of the opposite case. Otherwise, return+ -- the argument unmodified.+ toCaseChar :: Case -> char -> char -{-| Manipulate a character as if it were an ASCII 'ASCII.Char', assuming that it is+class ToCasefulChar (letterCase :: Case) (char :: Type) where+ toCasefulChar :: CaselessChar -> char -Defined only where 'isAsciiChar' is satisfied. -}+-- | Manipulate a character as if it were an ASCII 'ASCII.Char', assuming that it is+--+-- Defined only where 'isAsciiChar' is satisfied. asCharUnsafe :: CharSuperset char => (ASCII.Char -> ASCII.Char) -> char -> char asCharUnsafe f = fromChar . f . toCharUnsafe @@ -117,11 +137,15 @@ toCaselessCharMaybe = toCaselessCharOrFail toCharOrFail :: (ToChar char, MonadFail context) => char -> context ASCII.Char-toCharOrFail x = if isAsciiChar x then return (toCharUnsafe x)+toCharOrFail x =+ if isAsciiChar x+ then return (toCharUnsafe x) else fail "Not an ASCII character" toCaselessCharOrFail :: (ToCaselessChar char, MonadFail context) => char -> context CaselessChar-toCaselessCharOrFail x = if isAsciiCaselessChar x then return (toCaselessCharUnsafe x)+toCaselessCharOrFail x =+ if isAsciiCaselessChar x+ then return (toCaselessCharUnsafe x) else fail "Not an ASCII character" toCharSub :: ToChar char => char -> ASCII.Char@@ -130,105 +154,101 @@ toCaselessCharSub :: ToCaselessChar char => char -> CaselessChar toCaselessCharSub x = if isAsciiCaselessChar x then toCaselessCharUnsafe x else Caseless.Substitute -{-| Force a character into ASCII by replacing it with 'ASCII.Substitute' if it- is not already an ASCII character--The resulting character satisfies 'isAsciiChar' and 'isAsciiCaselessChar'. -}+-- | Force a character into ASCII by replacing it with 'ASCII.Substitute' if it+-- is not already an ASCII character+--+-- The resulting character satisfies 'isAsciiChar' and 'isAsciiCaselessChar'. substituteChar :: CharSuperset char => char -> char substituteChar x = if isAsciiChar x then x else fromChar ASCII.Substitute -{-| Convert from one ASCII-superset character type to another via the ASCII-'ASCII.Char' type. Fails as 'Nothing' if the input is outside the ASCII-character set. -}+-- | Convert from one ASCII-superset character type to another via the ASCII+-- 'ASCII.Char' type. Fails as 'Nothing' if the input is outside the ASCII+-- character set. convertCharMaybe :: (ToChar char1, FromChar char2) => char1 -> Maybe char2 convertCharMaybe = convertCharOrFail -{-| Convert from one ASCII-superset character type to another via the ASCII-'ASCII.Char' type. Fails with 'fail' if the input is outside the ASCII character-set. -}-convertCharOrFail :: (ToChar char1, FromChar char2, MonadFail context) =>- char1 -> context char2+-- | Convert from one ASCII-superset character type to another via the ASCII+-- 'ASCII.Char' type. Fails with 'fail' if the input is outside the ASCII character+-- set.+convertCharOrFail ::+ (ToChar char1, FromChar char2, MonadFail context) =>+ char1 ->+ context char2 convertCharOrFail = fmap fromChar . toCharOrFail - --- String --- -{-| Partial conversion to @['CaselessChar']@--Generally this will be a superset of ASCII strings with a 'ToString' instance as-well, and the conversion will be achieved by discarding the case of letters. A-notable exception is the instance for @['CaselessChar']@ type itself, which is-already represented without case and does not have a 'ToString' instance. -}-class ToCaselessString string where-- -- | Test whether a character can be converted to @['CaselessChar']@- isAsciiCaselessString :: string -> Bool-- {-| Conversion to @['CaselessChar']@, defined only where- 'isAsciiCaselessString' is satisfied -}- toCaselessCharListUnsafe :: string -> [CaselessChar]-- {-| Conversion to @['CaselessChar']@ achieved by using- 'Caseless.Substitute' in place of any non-ASCII characters -}- toCaselessCharListSub :: string -> [CaselessChar]--{-| Partial conversion to @['ASCII.Char']@--This includes @['ASCII.Char']@ type itself, strings of character sets that are-supersets of ASCII, and sequences of numeric types such as 'Word8' that are-often used to represent ASCII characters.--This does /not/ include @['CaselessChar']@, because that cannot be converted-to @['ASCII.Char']@ without choosing a case. -}-class ToCaselessString string => ToString string where-- -- | Test whether a string can be converted to @['ASCII.Char']@- isAsciiString :: string -> Bool-- {-| Conversion to @['ASCII.Char']@, defined only where 'isAsciiString'- is satisfied -}- toCharListUnsafe :: string -> [ASCII.Char]-- {-| Conversion to @['ASCII.Char']@ achieved by using- 'ASCII.Substitute' in place of any non-ASCII characters -}- toCharListSub :: string -> [ASCII.Char]--{-| Total conversion from @['ASCII.Char']@--This class includes supersets of ASCII, in which case 'fromCharList' lifts each-character into the larger character set. It also includes @['CaselessChar']@, in-which case 'fromCharList' discards case information from letters.+-- | Partial conversion to @['CaselessChar']@+--+-- Generally this will be a superset of ASCII strings with a 'ToString' instance as+-- well, and the conversion will be achieved by discarding the case of letters. A+-- notable exception is the instance for @['CaselessChar']@ type itself, which is+-- already represented without case and does not have a 'ToString' instance.+class ToCaselessString (string :: Type) where+ -- | Test whether a character can be converted to @['CaselessChar']@+ isAsciiCaselessString :: string -> Bool -This does /not/ include @['ASCII.CaseRefinement.ASCII'case']@, because that-represents a subset of ASCII; not all ASCII characters are of case wanted by-'ASCII.CaseRefinement.ASCII'case', so no total conversion is possible without-changing case. -}-class FromString string where+ -- | Conversion to @['CaselessChar']@, defined only where+ -- 'isAsciiCaselessString' is satisfied+ toCaselessCharListUnsafe :: string -> [CaselessChar] - -- | Conversion from @['ASCII.Char']@- fromCharList :: [ASCII.Char] -> string+ -- | Conversion to @['CaselessChar']@ achieved by using+ -- 'Caseless.Substitute' in place of any non-ASCII characters+ toCaselessCharListSub :: string -> [CaselessChar] -{- | String type with:+-- | Partial conversion to @['ASCII.Char']@+--+-- This includes @['ASCII.Char']@ type itself, strings of character sets that are+-- supersets of ASCII, and sequences of numeric types such as 'Word8' that are+-- often used to represent ASCII characters.+--+-- This does /not/ include @['CaselessChar']@, because that cannot be converted+-- to @['ASCII.Char']@ without choosing a case.+class ToCaselessString string => ToString (string :: Type) where+ -- | Test whether a string can be converted to @['ASCII.Char']@+ isAsciiString :: string -> Bool -- a total conversion from ASCII; and-- a partial conversion to ASCII -}-class (ToString string, FromString string) => StringSuperset string where+ -- | Conversion to @['ASCII.Char']@, defined only where 'isAsciiString'+ -- is satisfied+ toCharListUnsafe :: string -> [ASCII.Char] - {-| Force a string into ASCII by replacing any non-ASCII character with 'ASCII.Substitute'+ -- | Conversion to @['ASCII.Char']@ achieved by using+ -- 'ASCII.Substitute' in place of any non-ASCII characters+ toCharListSub :: string -> [ASCII.Char] - The resulting string satisfies 'isAsciiString' and 'isAsciiCaselessString'. -}- substituteString :: string -> string+-- | Total conversion from @['ASCII.Char']@+--+-- This class includes supersets of ASCII, in which case 'fromCharList' lifts each+-- character into the larger character set. It also includes @['CaselessChar']@, in+-- which case 'fromCharList' discards case information from letters.+--+-- This does /not/ include @['ASCII.CaseRefinement.ASCII'case']@, because that+-- represents a subset of ASCII; not all ASCII characters are of case wanted by+-- 'ASCII.CaseRefinement.ASCII'case', so no total conversion is possible without+-- changing case.+class FromString (string :: Type) where+ -- | Conversion from @['ASCII.Char']@+ fromCharList :: [ASCII.Char] -> string - mapCharsUnsafe :: (ASCII.Char -> ASCII.Char) -> string -> string- mapCharsUnsafe f = fromCharList . List.map f . toCharListUnsafe+-- | String type with:+--+-- - a total conversion from ASCII; and+-- - a partial conversion to ASCII+class (ToString string, FromString string) => StringSuperset (string :: Type) where+ -- | Force a string into ASCII by replacing any non-ASCII character with 'ASCII.Substitute'+ --+ -- The resulting string satisfies 'isAsciiString' and 'isAsciiCaselessString'.+ substituteString :: string -> string - {- | Convert each character in the superset to the designated case, if it is- an ASCII letter of the opposite case. Leaves other characters unchanged. -}- toCaseString :: Case -> string -> string+ mapCharsUnsafe :: (ASCII.Char -> ASCII.Char) -> string -> string+ mapCharsUnsafe f = fromCharList . List.map f . toCharListUnsafe -class ToCasefulString (letterCase :: Case) string where+ -- | Convert each character in the superset to the designated case, if it is+ -- an ASCII letter of the opposite case. Leaves other characters unchanged.+ toCaseString :: Case -> string -> string - toCasefulString :: [CaselessChar] -> string+class ToCasefulString (letterCase :: Case) (string :: Type) where+ toCasefulString :: [CaselessChar] -> string toCharListMaybe :: ToString string => string -> Maybe [ASCII.Char] toCharListMaybe = toCharListOrFail@@ -236,303 +256,314 @@ toCaselessCharListMaybe :: ToCaselessString string => string -> Maybe [CaselessChar] toCaselessCharListMaybe = toCaselessCharListOrFail -toCharListOrFail :: (ToString string, MonadFail context) =>- string -> context [ASCII.Char]-toCharListOrFail x = if isAsciiString x then return (toCharListUnsafe x)+toCharListOrFail ::+ (ToString string, MonadFail context) =>+ string ->+ context [ASCII.Char]+toCharListOrFail x =+ if isAsciiString x+ then return (toCharListUnsafe x) else fail "String contains non-ASCII characters" -toCaselessCharListOrFail :: (ToCaselessString string, MonadFail context) =>- string -> context [CaselessChar]-toCaselessCharListOrFail x = if isAsciiCaselessString x then return (toCaselessCharListUnsafe x)+toCaselessCharListOrFail ::+ (ToCaselessString string, MonadFail context) =>+ string ->+ context [CaselessChar]+toCaselessCharListOrFail x =+ if isAsciiCaselessString x+ then return (toCaselessCharListUnsafe x) else fail "String contains non-ASCII characters" -{-| Convert from one ASCII-superset string type to another by converting each-character of the input string to an ASCII 'ASCII.Char', and then converting the-ASCII character list to the desired output type. Fails as 'Nothing' if the input-contains any character that is outside the ASCII character set. -}-convertStringMaybe :: (ToString string1, FromString string2) =>- string1 -> Maybe string2+-- | Convert from one ASCII-superset string type to another by converting each+-- character of the input string to an ASCII 'ASCII.Char', and then converting the+-- ASCII character list to the desired output type. Fails as 'Nothing' if the input+-- contains any character that is outside the ASCII character set.+convertStringMaybe ::+ (ToString string1, FromString string2) =>+ string1 ->+ Maybe string2 convertStringMaybe = convertStringOrFail -{-| Convert from one ASCII-superset string type to another by converting each-character of the input string to an ASCII 'ASCII.Char', and then converting the-ASCII character list to the desired output type. Fails with 'fail' if the input-contains any character that is outside the ASCII character set. -}-convertStringOrFail :: (ToString string1, FromString string2, MonadFail context) =>- string1 -> context string2+-- | Convert from one ASCII-superset string type to another by converting each+-- character of the input string to an ASCII 'ASCII.Char', and then converting the+-- ASCII character list to the desired output type. Fails with 'fail' if the input+-- contains any character that is outside the ASCII character set.+convertStringOrFail ::+ (ToString string1, FromString string2, MonadFail context) =>+ string1 ->+ context string2 convertStringOrFail = fmap fromCharList . toCharListOrFail - --- Instances --- -- | 'CaselessChar' is trivially convertible to itself. instance ToCaselessChar CaselessChar where- isAsciiCaselessChar _ = Bool.True- toCaselessCharUnsafe = id+ isAsciiCaselessChar _ = Bool.True+ toCaselessCharUnsafe = id instance FromChar CaselessChar where- fromChar = Caseless.disregardCase+ fromChar = Caseless.disregardCase --- instance ToCaselessChar ASCII.Char where- isAsciiCaselessChar _ = Bool.True- toCaselessCharUnsafe = Caseless.disregardCase+ isAsciiCaselessChar _ = Bool.True+ toCaselessCharUnsafe = Caseless.disregardCase instance ToChar ASCII.Char where- isAsciiChar _ = Bool.True- toCharUnsafe = id+ isAsciiChar _ = Bool.True+ toCharUnsafe = id instance FromChar ASCII.Char where- fromChar = id+ fromChar = id -- | 'ASCII.Char' is trivially a superset of itself. instance CharSuperset ASCII.Char where- toCaseChar = Case.toCase+ toCaseChar = Case.toCase instance KnownCase letterCase => ToCasefulChar letterCase ASCII.Char where- toCasefulChar = Caseless.toCase (theCase @letterCase)+ toCasefulChar = Caseless.toCase (theCase @letterCase) --- instance ToCaselessChar Unicode.Char where- isAsciiCaselessChar = isAsciiChar- toCaselessCharUnsafe = toCaselessCharUnsafe . toCharUnsafe+ isAsciiCaselessChar = isAsciiChar+ toCaselessCharUnsafe = toCaselessCharUnsafe . toCharUnsafe instance ToChar Unicode.Char where- isAsciiChar = (<= '\DEL')- toCharUnsafe = toCharUnsafe @Int.Int . Unicode.ord+ isAsciiChar = (<= '\DEL')+ toCharUnsafe = toCharUnsafe @Int.Int . Unicode.ord instance FromChar Unicode.Char where- fromChar = Unicode.chr . ASCII.toInt+ fromChar = Unicode.chr . ASCII.toInt instance CharSuperset Unicode.Char where- toCaseChar UpperCase x | x >= 'a' && x <= 'z' = Unicode.chr (Unicode.ord x - 32)- toCaseChar LowerCase x | x >= 'A' && x <= 'Z' = Unicode.chr (Unicode.ord x + 32)- toCaseChar _ x = x+ toCaseChar UpperCase x | x >= 'a' && x <= 'z' = Unicode.chr (Unicode.ord x - 32)+ toCaseChar LowerCase x | x >= 'A' && x <= 'Z' = Unicode.chr (Unicode.ord x + 32)+ toCaseChar _ x = x instance KnownCase letterCase => ToCasefulChar letterCase Unicode.Char where- toCasefulChar = fromChar . toCasefulChar @letterCase+ toCasefulChar = fromChar . toCasefulChar @letterCase --- instance ToCaselessChar Nat.Natural where- isAsciiCaselessChar = isAsciiChar- toCaselessCharUnsafe = toCaselessCharUnsafe . toCharUnsafe+ isAsciiCaselessChar = isAsciiChar+ toCaselessCharUnsafe = toCaselessCharUnsafe . toCharUnsafe instance ToChar Nat.Natural where- isAsciiChar = (<= 127)- toCharUnsafe = toCharUnsafe @Int.Int . Prelude.fromIntegral+ isAsciiChar = (<= 127)+ toCharUnsafe = toCharUnsafe @Int.Int . Prelude.fromIntegral instance FromChar Nat.Natural where- fromChar = Prelude.fromIntegral . ASCII.toInt+ fromChar = Prelude.fromIntegral . ASCII.toInt instance CharSuperset Nat.Natural where- toCaseChar UpperCase x | x >= 97 && x <= 122 = x - 32- toCaseChar LowerCase x | x >= 65 && x <= 90 = x + 32- toCaseChar _ x = x+ toCaseChar UpperCase x | x >= 97 && x <= 122 = x - 32+ toCaseChar LowerCase x | x >= 65 && x <= 90 = x + 32+ toCaseChar _ x = x instance KnownCase letterCase => ToCasefulChar letterCase Nat.Natural where- toCasefulChar = fromChar . toCasefulChar @letterCase+ toCasefulChar = fromChar . toCasefulChar @letterCase --- instance ToCaselessChar Int.Int where- isAsciiCaselessChar = isAsciiChar- toCaselessCharUnsafe = toCaselessCharUnsafe . toCharUnsafe+ isAsciiCaselessChar = isAsciiChar+ toCaselessCharUnsafe = toCaselessCharUnsafe . toCharUnsafe instance ToChar Int.Int where- isAsciiChar x = (x >= 0) && (x <= 127)- toCharUnsafe = ASCII.fromIntUnsafe+ isAsciiChar x = (x >= 0) && (x <= 127)+ toCharUnsafe = ASCII.fromIntUnsafe instance FromChar Int.Int where- fromChar = ASCII.toInt+ fromChar = ASCII.toInt instance CharSuperset Int.Int where- toCaseChar UpperCase x | x >= 97 && x <= 122 = x - 32- toCaseChar LowerCase x | x >= 65 && x <= 90 = x + 32- toCaseChar _ x = x+ toCaseChar UpperCase x | x >= 97 && x <= 122 = x - 32+ toCaseChar LowerCase x | x >= 65 && x <= 90 = x + 32+ toCaseChar _ x = x instance KnownCase letterCase => ToCasefulChar letterCase Int.Int where- toCasefulChar = fromChar . toCasefulChar @letterCase+ toCasefulChar = fromChar . toCasefulChar @letterCase --- instance ToCaselessChar Word.Word8 where- isAsciiCaselessChar = isAsciiChar- toCaselessCharUnsafe = toCaselessCharUnsafe . toCharUnsafe+ isAsciiCaselessChar = isAsciiChar+ toCaselessCharUnsafe = toCaselessCharUnsafe . toCharUnsafe instance ToChar Word.Word8 where- isAsciiChar = (<= 127)- toCharUnsafe = ASCII.fromIntUnsafe . Prelude.fromIntegral+ isAsciiChar = (<= 127)+ toCharUnsafe = ASCII.fromIntUnsafe . Prelude.fromIntegral instance FromChar Word.Word8 where- fromChar = Prelude.fromIntegral . ASCII.toInt+ fromChar = Prelude.fromIntegral . ASCII.toInt instance CharSuperset Word.Word8 where- toCaseChar UpperCase x | x >= 97 && x <= 122 = x - 32- toCaseChar LowerCase x | x >= 65 && x <= 90 = x + 32- toCaseChar _ x = x+ toCaseChar UpperCase x | x >= 97 && x <= 122 = x - 32+ toCaseChar LowerCase x | x >= 65 && x <= 90 = x + 32+ toCaseChar _ x = x instance KnownCase letterCase => ToCasefulChar letterCase Word.Word8 where- toCasefulChar = fromChar . toCasefulChar @letterCase+ toCasefulChar = fromChar . toCasefulChar @letterCase --- instance ToCaselessChar char => ToCaselessString [char] where- isAsciiCaselessString = List.all isAsciiCaselessChar- toCaselessCharListUnsafe = List.map toCaselessCharUnsafe- toCaselessCharListSub = List.map toCaselessCharSub+ isAsciiCaselessString = List.all isAsciiCaselessChar+ toCaselessCharListUnsafe = List.map toCaselessCharUnsafe+ toCaselessCharListSub = List.map toCaselessCharSub instance ToChar char => ToString [char] where- isAsciiString = List.all isAsciiChar- toCharListUnsafe = List.map toCharUnsafe- toCharListSub = List.map toCharSub+ isAsciiString = List.all isAsciiChar+ toCharListUnsafe = List.map toCharUnsafe+ toCharListSub = List.map toCharSub instance FromChar char => FromString [char] where- fromCharList = List.map fromChar+ fromCharList = List.map fromChar instance CharSuperset char => StringSuperset [char] where- substituteString = List.map substituteChar- toCaseString c = List.map (toCaseChar c)+ substituteString = List.map substituteChar+ toCaseString c = List.map (toCaseChar c) instance (ToCasefulChar letterCase char, KnownCase letterCase) => ToCasefulString letterCase [char] where- toCasefulString = List.map (toCasefulChar @letterCase)+ toCasefulString = List.map (toCasefulChar @letterCase) --- instance ToCaselessString T.Text where- isAsciiCaselessString = T.all isAsciiChar- toCaselessCharListUnsafe = toCaselessCharListUnsafe . T.unpack- toCaselessCharListSub = toCaselessCharListSub . T.unpack+ isAsciiCaselessString = T.all isAsciiChar+ toCaselessCharListUnsafe = toCaselessCharListUnsafe . T.unpack+ toCaselessCharListSub = toCaselessCharListSub . T.unpack instance ToString T.Text where- isAsciiString = T.all isAsciiChar- toCharListUnsafe = toCharListUnsafe . T.unpack- toCharListSub = toCharListSub . T.unpack+ isAsciiString = T.all isAsciiChar+ toCharListUnsafe = toCharListUnsafe . T.unpack+ toCharListSub = toCharListSub . T.unpack instance FromString T.Text where- fromCharList = T.pack . fromCharList+ fromCharList = T.pack . fromCharList instance StringSuperset T.Text where- substituteString = T.map substituteChar- mapCharsUnsafe f = T.map (asCharUnsafe f)- toCaseString c = T.map (toCaseChar c)+ substituteString = T.map substituteChar+ mapCharsUnsafe f = T.map (asCharUnsafe f)+ toCaseString c = T.map (toCaseChar c) instance KnownCase letterCase => ToCasefulString letterCase T.Text where- toCasefulString = fromCharList . toCasefulString @letterCase+ toCasefulString = fromCharList . toCasefulString @letterCase --- instance ToCaselessString LT.Text where- isAsciiCaselessString = LT.all isAsciiChar- toCaselessCharListUnsafe = toCaselessCharListUnsafe . LT.unpack- toCaselessCharListSub = toCaselessCharListSub . LT.unpack+ isAsciiCaselessString = LT.all isAsciiChar+ toCaselessCharListUnsafe = toCaselessCharListUnsafe . LT.unpack+ toCaselessCharListSub = toCaselessCharListSub . LT.unpack instance ToString LT.Text where- isAsciiString = LT.all isAsciiChar- toCharListUnsafe = toCharListUnsafe . LT.unpack- toCharListSub = toCharListSub . LT.unpack+ isAsciiString = LT.all isAsciiChar+ toCharListUnsafe = toCharListUnsafe . LT.unpack+ toCharListSub = toCharListSub . LT.unpack instance FromString LT.Text where- fromCharList = LT.pack . fromCharList+ fromCharList = LT.pack . fromCharList instance StringSuperset LT.Text where- substituteString = LT.map substituteChar- mapCharsUnsafe f = LT.map (asCharUnsafe f)- toCaseString c = LT.map (toCaseChar c)+ substituteString = LT.map substituteChar+ mapCharsUnsafe f = LT.map (asCharUnsafe f)+ toCaseString c = LT.map (toCaseChar c) instance KnownCase letterCase => ToCasefulString letterCase LT.Text where- toCasefulString = fromCharList . toCasefulString @letterCase+ toCasefulString = fromCharList . toCasefulString @letterCase --- instance ToCaselessString TB.Builder where- isAsciiCaselessString = isAsciiCaselessString . TB.toLazyText- toCaselessCharListUnsafe = toCaselessCharListUnsafe . TB.toLazyText- toCaselessCharListSub = toCaselessCharListSub . TB.toLazyText+ isAsciiCaselessString = isAsciiCaselessString . TB.toLazyText+ toCaselessCharListUnsafe = toCaselessCharListUnsafe . TB.toLazyText+ toCaselessCharListSub = toCaselessCharListSub . TB.toLazyText instance ToString TB.Builder where- isAsciiString = isAsciiString . TB.toLazyText- toCharListUnsafe = toCharListUnsafe . TB.toLazyText- toCharListSub = toCharListSub . TB.toLazyText+ isAsciiString = isAsciiString . TB.toLazyText+ toCharListUnsafe = toCharListUnsafe . TB.toLazyText+ toCharListSub = toCharListSub . TB.toLazyText instance FromString TB.Builder where- fromCharList = TB.fromString . fromCharList+ fromCharList = TB.fromString . fromCharList instance StringSuperset TB.Builder where- substituteString = TB.fromLazyText . substituteString . TB.toLazyText- mapCharsUnsafe f = TB.fromLazyText . mapCharsUnsafe f . TB.toLazyText- toCaseString c = TB.fromLazyText . toCaseString c . TB.toLazyText+ substituteString = TB.fromLazyText . substituteString . TB.toLazyText+ mapCharsUnsafe f = TB.fromLazyText . mapCharsUnsafe f . TB.toLazyText+ toCaseString c = TB.fromLazyText . toCaseString c . TB.toLazyText instance KnownCase letterCase => ToCasefulString letterCase TB.Builder where- toCasefulString = fromCharList . toCasefulString @letterCase+ toCasefulString = fromCharList . toCasefulString @letterCase --- instance ToCaselessString BS.ByteString where- isAsciiCaselessString = BS.all isAsciiCaselessChar- toCaselessCharListUnsafe = toCaselessCharListUnsafe . BS.unpack- toCaselessCharListSub = toCaselessCharListSub . BS.unpack+ isAsciiCaselessString = BS.all isAsciiCaselessChar+ toCaselessCharListUnsafe = toCaselessCharListUnsafe . BS.unpack+ toCaselessCharListSub = toCaselessCharListSub . BS.unpack instance ToString BS.ByteString where- isAsciiString = BS.all isAsciiChar- toCharListUnsafe = toCharListUnsafe . BS.unpack- toCharListSub = toCharListSub . BS.unpack+ isAsciiString = BS.all isAsciiChar+ toCharListUnsafe = toCharListUnsafe . BS.unpack+ toCharListSub = toCharListSub . BS.unpack instance FromString BS.ByteString where- fromCharList = BS.pack . fromCharList+ fromCharList = BS.pack . fromCharList instance StringSuperset BS.ByteString where- substituteString = BS.map substituteChar- mapCharsUnsafe f = BS.map (asCharUnsafe f)- toCaseString c = BS.map (toCaseChar c)+ substituteString = BS.map substituteChar+ mapCharsUnsafe f = BS.map (asCharUnsafe f)+ toCaseString c = BS.map (toCaseChar c) instance KnownCase letterCase => ToCasefulString letterCase BS.ByteString where- toCasefulString = fromCharList . toCasefulString @letterCase+ toCasefulString = fromCharList . toCasefulString @letterCase --- instance ToCaselessString LBS.ByteString where- isAsciiCaselessString = LBS.all isAsciiCaselessChar- toCaselessCharListUnsafe = toCaselessCharListUnsafe . LBS.unpack- toCaselessCharListSub = toCaselessCharListSub . LBS.unpack+ isAsciiCaselessString = LBS.all isAsciiCaselessChar+ toCaselessCharListUnsafe = toCaselessCharListUnsafe . LBS.unpack+ toCaselessCharListSub = toCaselessCharListSub . LBS.unpack instance ToString LBS.ByteString where- isAsciiString = LBS.all isAsciiChar- toCharListUnsafe = toCharListUnsafe . LBS.unpack- toCharListSub = toCharListSub . LBS.unpack+ isAsciiString = LBS.all isAsciiChar+ toCharListUnsafe = toCharListUnsafe . LBS.unpack+ toCharListSub = toCharListSub . LBS.unpack instance FromString LBS.ByteString where- fromCharList = LBS.pack . fromCharList+ fromCharList = LBS.pack . fromCharList instance StringSuperset LBS.ByteString where- substituteString = LBS.map substituteChar- mapCharsUnsafe f = LBS.map (asCharUnsafe f)- toCaseString c = LBS.map (toCaseChar c)+ substituteString = LBS.map substituteChar+ mapCharsUnsafe f = LBS.map (asCharUnsafe f)+ toCaseString c = LBS.map (toCaseChar c) instance KnownCase letterCase => ToCasefulString letterCase LBS.ByteString where- toCasefulString = fromCharList . toCasefulString @letterCase+ toCasefulString = fromCharList . toCasefulString @letterCase --- instance ToCaselessString BSB.Builder where- isAsciiCaselessString = isAsciiCaselessString . BSB.toLazyByteString- toCaselessCharListUnsafe = toCaselessCharListUnsafe . BSB.toLazyByteString- toCaselessCharListSub = toCaselessCharListSub . BSB.toLazyByteString+ isAsciiCaselessString = isAsciiCaselessString . BSB.toLazyByteString+ toCaselessCharListUnsafe = toCaselessCharListUnsafe . BSB.toLazyByteString+ toCaselessCharListSub = toCaselessCharListSub . BSB.toLazyByteString instance ToString BSB.Builder where- isAsciiString = isAsciiString . BSB.toLazyByteString- toCharListUnsafe = toCharListUnsafe . BSB.toLazyByteString- toCharListSub = toCharListSub . BSB.toLazyByteString+ isAsciiString = isAsciiString . BSB.toLazyByteString+ toCharListUnsafe = toCharListUnsafe . BSB.toLazyByteString+ toCharListSub = toCharListSub . BSB.toLazyByteString instance FromString BSB.Builder where- fromCharList = BSB.lazyByteString . fromCharList+ fromCharList = BSB.lazyByteString . fromCharList instance StringSuperset BSB.Builder where- substituteString = BSB.lazyByteString . substituteString . BSB.toLazyByteString- mapCharsUnsafe f = BSB.lazyByteString . mapCharsUnsafe f . BSB.toLazyByteString- toCaseString c = BSB.lazyByteString . toCaseString c . BSB.toLazyByteString+ substituteString = BSB.lazyByteString . substituteString . BSB.toLazyByteString+ mapCharsUnsafe f = BSB.lazyByteString . mapCharsUnsafe f . BSB.toLazyByteString+ toCaseString c = BSB.lazyByteString . toCaseString c . BSB.toLazyByteString instance KnownCase letterCase => ToCasefulString letterCase BSB.Builder where- toCasefulString = fromCharList . toCasefulString @letterCase+ toCasefulString = fromCharList . toCasefulString @letterCase
library/ASCII/Superset/Text.hs view
@@ -1,74 +1,74 @@ module ASCII.Superset.Text where import ASCII.CaseRefinement (ASCII'case)+import ASCII.CaseRefinement qualified as CaseRefinement import ASCII.Refinement (ASCII)+import ASCII.Refinement qualified as Refinement+import Data.ByteString qualified as Strict (ByteString)+import Data.ByteString.Lazy qualified as Lazy (ByteString)+import Data.Char qualified as Unicode import Data.Function (id, (.))--import qualified ASCII.CaseRefinement as CaseRefinement-import qualified ASCII.Refinement as Refinement-import qualified Data.ByteString as Strict (ByteString)-import qualified Data.ByteString.Lazy as Lazy (ByteString)-import qualified Data.Char as Unicode-import qualified Data.Text as Strict (Text)-import qualified Data.Text as Text.Strict-import qualified Data.Text.Encoding as Text.Strict-import qualified Data.Text.Lazy as Lazy (Text)-import qualified Data.Text.Lazy as Text.Lazy-import qualified Data.Text.Lazy.Encoding as Text.Lazy+import Data.Kind (Type)+import Data.Text qualified as Strict (Text)+import Data.Text qualified as Text.Strict+import Data.Text.Encoding qualified as Text.Strict+import Data.Text.Lazy qualified as Lazy (Text)+import Data.Text.Lazy qualified as Text.Lazy+import Data.Text.Lazy.Encoding qualified as Text.Lazy -class ToText a where- toStrictText :: a -> Strict.Text- toStrictText = Text.Lazy.toStrict . toLazyText+class ToText (a :: Type) where+ toStrictText :: a -> Strict.Text+ toStrictText = Text.Lazy.toStrict . toLazyText - toLazyText :: a -> Lazy.Text- toLazyText = Text.Lazy.fromStrict . toStrictText+ toLazyText :: a -> Lazy.Text+ toLazyText = Text.Lazy.fromStrict . toStrictText - toUnicodeCharList :: a -> [Unicode.Char]- toUnicodeCharList = Text.Lazy.unpack . toLazyText+ toUnicodeCharList :: a -> [Unicode.Char]+ toUnicodeCharList = Text.Lazy.unpack . toLazyText - {-# minimal toStrictText | toLazyText #-}+ {-# MINIMAL toStrictText | toLazyText #-} instance ToText Strict.Text where- toStrictText = id+ toStrictText = id instance ToText Lazy.Text where- toLazyText = id+ toLazyText = id instance ToText [Unicode.Char] where- toUnicodeCharList = id- toStrictText = Text.Strict.pack- toLazyText = Text.Lazy.pack+ toUnicodeCharList = id+ toStrictText = Text.Strict.pack+ toLazyText = Text.Lazy.pack instance ToText (ASCII Strict.Text) where- toStrictText = Refinement.lift+ toStrictText = Refinement.lift instance ToText (ASCII Lazy.Text) where- toLazyText = Refinement.lift+ toLazyText = Refinement.lift instance ToText (ASCII Strict.ByteString) where- toStrictText = Text.Strict.decodeUtf8 . Refinement.lift+ toStrictText = Text.Strict.decodeUtf8 . Refinement.lift instance ToText (ASCII Lazy.ByteString) where- toLazyText = Text.Lazy.decodeUtf8 . Refinement.lift+ toLazyText = Text.Lazy.decodeUtf8 . Refinement.lift instance ToText (ASCII [Unicode.Char]) where- toUnicodeCharList = Refinement.lift- toStrictText = Text.Strict.pack . Refinement.lift- toLazyText = Text.Lazy.pack . Refinement.lift+ toUnicodeCharList = Refinement.lift+ toStrictText = Text.Strict.pack . Refinement.lift+ toLazyText = Text.Lazy.pack . Refinement.lift instance ToText (ASCII'case letterCase Strict.Text) where- toStrictText = Refinement.lift . CaseRefinement.forgetCase+ toStrictText = Refinement.lift . CaseRefinement.forgetCase instance ToText (ASCII'case letterCase Lazy.Text) where- toLazyText = Refinement.lift . CaseRefinement.forgetCase+ toLazyText = Refinement.lift . CaseRefinement.forgetCase instance ToText (ASCII'case letterCase Strict.ByteString) where- toStrictText = Text.Strict.decodeUtf8 . Refinement.lift . CaseRefinement.forgetCase+ toStrictText = Text.Strict.decodeUtf8 . Refinement.lift . CaseRefinement.forgetCase instance ToText (ASCII'case letterCase Lazy.ByteString) where- toLazyText = Text.Lazy.decodeUtf8 . Refinement.lift . CaseRefinement.forgetCase+ toLazyText = Text.Lazy.decodeUtf8 . Refinement.lift . CaseRefinement.forgetCase instance ToText (ASCII'case letterCase [Unicode.Char]) where- toUnicodeCharList = Refinement.lift . CaseRefinement.forgetCase- toStrictText = Text.Strict.pack . Refinement.lift . CaseRefinement.forgetCase- toLazyText = Text.Lazy.pack . Refinement.lift . CaseRefinement.forgetCase+ toUnicodeCharList = Refinement.lift . CaseRefinement.forgetCase+ toStrictText = Text.Strict.pack . Refinement.lift . CaseRefinement.forgetCase+ toLazyText = Text.Lazy.pack . Refinement.lift . CaseRefinement.forgetCase
library/ASCII/SupersetConversion.hs view
@@ -1,73 +1,77 @@ module ASCII.SupersetConversion- (- {- * Class -} StringSupersetConversion (..),- {- * Utilities -} convertRefinedString,+ ( -- * Class+ StringSupersetConversion (..),++ -- * Utilities+ convertRefinedString, )- where+where +import {-# SOURCE #-} ASCII.Refinement.Internal (convertRefinedString) import ASCII.Superset--import {-# source #-} ASCII.Refinement.Internal (convertRefinedString)--import qualified Data.ByteString as BS-import qualified Data.ByteString.Char8 as BS.Char8-import qualified Data.ByteString.Lazy as LBS-import qualified Data.ByteString.Lazy.Char8 as LBS.Char8-import qualified Data.Char as Unicode-import qualified Data.Text as T-import qualified Data.Text.Encoding as T-import qualified Data.Text.Lazy as LT-import qualified Data.Text.Lazy.Encoding as LT+import Data.ByteString qualified as BS+import Data.ByteString.Char8 qualified as BS.Char8+import Data.ByteString.Lazy qualified as LBS+import Data.ByteString.Lazy.Char8 qualified as LBS.Char8+import Data.Char qualified as Unicode+import Data.Kind (Type)+import Data.Text qualified as T+import Data.Text.Encoding qualified as T+import Data.Text.Lazy qualified as LT+import Data.Text.Lazy.Encoding qualified as LT -class (StringSuperset a, StringSuperset b) => StringSupersetConversion a b where- convertStringUnsafe :: a -> b+class+ (StringSuperset a, StringSuperset b) =>+ StringSupersetConversion (a :: Type) (b :: Type)+ where+ convertStringUnsafe :: a -> b instance StringSupersetConversion T.Text BS.ByteString where- convertStringUnsafe = T.encodeUtf8+ convertStringUnsafe = T.encodeUtf8 instance StringSupersetConversion BS.ByteString T.Text where- convertStringUnsafe = T.decodeUtf8+ convertStringUnsafe = T.decodeUtf8 instance StringSupersetConversion LT.Text LBS.ByteString where- convertStringUnsafe = LT.encodeUtf8+ convertStringUnsafe = LT.encodeUtf8 instance StringSupersetConversion LBS.ByteString LT.Text where- convertStringUnsafe = LT.decodeUtf8+ convertStringUnsafe = LT.decodeUtf8 instance StringSupersetConversion T.Text LT.Text where- convertStringUnsafe = LT.fromStrict+ convertStringUnsafe = LT.fromStrict instance StringSupersetConversion LT.Text T.Text where- convertStringUnsafe = LT.toStrict+ convertStringUnsafe = LT.toStrict instance StringSupersetConversion BS.ByteString LBS.ByteString where- convertStringUnsafe = LBS.fromStrict+ convertStringUnsafe = LBS.fromStrict instance StringSupersetConversion LBS.ByteString BS.ByteString where- convertStringUnsafe = LBS.toStrict+ convertStringUnsafe = LBS.toStrict --- instance StringSupersetConversion T.Text [Unicode.Char] where- convertStringUnsafe = T.unpack+ convertStringUnsafe = T.unpack instance StringSupersetConversion [Unicode.Char] T.Text where- convertStringUnsafe = T.pack+ convertStringUnsafe = T.pack instance StringSupersetConversion LT.Text [Unicode.Char] where- convertStringUnsafe = LT.unpack+ convertStringUnsafe = LT.unpack instance StringSupersetConversion [Unicode.Char] LT.Text where- convertStringUnsafe = LT.pack+ convertStringUnsafe = LT.pack instance StringSupersetConversion BS.ByteString [Unicode.Char] where- convertStringUnsafe = BS.Char8.unpack+ convertStringUnsafe = BS.Char8.unpack instance StringSupersetConversion [Unicode.Char] BS.ByteString where- convertStringUnsafe = BS.Char8.pack+ convertStringUnsafe = BS.Char8.pack instance StringSupersetConversion LBS.ByteString [Unicode.Char] where- convertStringUnsafe = LBS.Char8.unpack+ convertStringUnsafe = LBS.Char8.unpack instance StringSupersetConversion [Unicode.Char] LBS.ByteString where- convertStringUnsafe = LBS.Char8.pack+ convertStringUnsafe = LBS.Char8.pack
library/ASCII/SupersetConversion.hs-boot view
@@ -1,6 +1,9 @@ module ASCII.SupersetConversion where import ASCII.Superset (StringSuperset)+import Data.Kind (Type) -class (StringSuperset a, StringSuperset b) => StringSupersetConversion a b where+class (StringSuperset a, StringSuperset b) =>+ StringSupersetConversion (a :: Type) (b :: Type)+ where convertStringUnsafe :: a -> b
test/Main.hs view
@@ -1,200 +1,197 @@ module Main (main) where -import Test.Hspec- import ASCII.Case (Case (..))+import ASCII.Case qualified as Case import ASCII.CaseRefinement (ASCII'lower, ASCII'upper, asciiCaseUnsafe)+import ASCII.CaseRefinement qualified as CaseRefinement+import ASCII.Caseless qualified as CC import ASCII.Char (Char (..))+import ASCII.Char qualified as ASCII import ASCII.Refinement (ASCII, asciiUnsafe)+import ASCII.Refinement qualified as Refinement import ASCII.Superset (fromChar, fromCharList)--import qualified ASCII.Case as Case-import qualified ASCII.Caseless as CC-import qualified ASCII.CaseRefinement as CaseRefinement-import qualified ASCII.Char as ASCII-import qualified ASCII.Refinement as Refinement-import qualified ASCII.Superset as Superset--import qualified Data.Foldable as Foldable-+import ASCII.Superset qualified as Superset+import Data.Char qualified as Unicode+import Data.Foldable qualified as Foldable import Data.Function ((&)) import Data.Text (Text) import Data.Word (Word8) import Numeric.Natural (Natural)+import Test.Hspec import Prelude -import qualified Data.Char as Unicode- main :: IO () main = hspec $ do-- describe "fromChar" $ do-- it "letter" $ do- let f x = fromChar x :: Word8- f CapitalLetterA `shouldBe` 65-- it "to unicode" $ do- let f = fromChar- f CapitalLetterA `shouldBe` 'A'-- it "id" $ do- let f x = fromChar (x :: ASCII.Char) :: ASCII.Char- f CapitalLetterA `shouldBe` CapitalLetterA-- describe "refinement" $ do-- it "validateChar" $ do- let f x = Refinement.validateChar x :: Maybe (ASCII Int)- f (-1) `shouldBe` Nothing- f 65 `shouldBe` Just (asciiUnsafe 65)- f 97 `shouldBe` Just (asciiUnsafe 97)- f 128 `shouldBe` Nothing-- describe "fromCharList" $ do- it "Text" $ do- let f x = fromCharList x :: Text- f [CapitalLetterH, SmallLetterI, ExclamationMark] `shouldBe` "Hi!"-- it "ASCII Text" $ do- let f x = Refinement.fromCharList x :: ASCII Text- f [CapitalLetterH, SmallLetterI, ExclamationMark] `shouldBe` asciiUnsafe "Hi!"-- it "toCharList" $ do- let f x = Refinement.toCharList- (Refinement.substituteString x :: ASCII Text)- f "Piñata" `shouldBe` [CapitalLetterP, SmallLetterI, Substitute,- SmallLetterA, SmallLetterT, SmallLetterA]-- it "substituteString" $ do- let f x = Refinement.substituteString x :: ASCII Text- f "Cristóbal" `shouldBe` asciiUnsafe "Crist\SUBbal"+ describe "fromChar" $ do+ it "letter" $ do+ let f x = fromChar x :: Word8+ f CapitalLetterA `shouldBe` 65 - it "validateString" $ do- let f x = Refinement.validateString x :: Maybe (ASCII Text)- f "Hello" `shouldBe` Just (asciiUnsafe "Hello")- f "Cristóbal" `shouldBe` Nothing+ it "to unicode" $ do+ let f = fromChar+ f CapitalLetterA `shouldBe` 'A' - describe "case refinement" $ do+ it "id" $ do+ let f x = fromChar (x :: ASCII.Char) :: ASCII.Char+ f CapitalLetterA `shouldBe` CapitalLetterA - describe "validateChar" $ do+ describe "refinement" $ do+ it "validateChar" $ do+ let f x = Refinement.validateChar x :: Maybe (ASCII Int)+ f (-1) `shouldBe` Nothing+ f 65 `shouldBe` Just (asciiUnsafe 65)+ f 97 `shouldBe` Just (asciiUnsafe 97)+ f 128 `shouldBe` Nothing - it "lower" $ do- let f x = CaseRefinement.validateChar x :: Maybe (ASCII'lower Int)- f (-1) `shouldBe` Nothing- f 65 `shouldBe` Nothing- f 97 `shouldBe` Just (asciiCaseUnsafe 97)- f 128 `shouldBe` Nothing+ describe "fromCharList" $ do+ it "Text" $ do+ let f x = fromCharList x :: Text+ f [CapitalLetterH, SmallLetterI, ExclamationMark] `shouldBe` "Hi!" - it "upper" $ do- let f x = CaseRefinement.validateChar x :: Maybe (ASCII'upper Int)- f (-1) `shouldBe` Nothing- f 65 `shouldBe` Just (asciiCaseUnsafe 65)- f 97 `shouldBe` Nothing- f 128 `shouldBe` Nothing+ it "ASCII Text" $ do+ let f x = Refinement.fromCharList x :: ASCII Text+ f [CapitalLetterH, SmallLetterI, ExclamationMark] `shouldBe` asciiUnsafe "Hi!" - describe "fromCaselessCharList" $ do+ it "toCharList" $ do+ let f x =+ Refinement.toCharList+ (Refinement.substituteString x :: ASCII Text)+ f "Piñata"+ `shouldBe` [ CapitalLetterP,+ SmallLetterI,+ Substitute,+ SmallLetterA,+ SmallLetterT,+ SmallLetterA+ ] - it "lower" $ do- let f x = CaseRefinement.fromCaselessCharList x :: ASCII'lower Text- f [CC.LetterH, CC.LetterI, CC.ExclamationMark] `shouldBe` asciiCaseUnsafe "hi!"+ it "substituteString" $ do+ let f x = Refinement.substituteString x :: ASCII Text+ f "Cristóbal" `shouldBe` asciiUnsafe "Crist\SUBbal" - it "upper" $ do- let f x = CaseRefinement.fromCaselessCharList x :: ASCII'upper Text- f [CC.LetterH, CC.LetterI, CC.ExclamationMark] `shouldBe` asciiCaseUnsafe "HI!"+ it "validateString" $ do+ let f x = Refinement.validateString x :: Maybe (ASCII Text)+ f "Hello" `shouldBe` Just (asciiUnsafe "Hello")+ f "Cristóbal" `shouldBe` Nothing - describe "toCaselessCharList" $ do+ describe "case refinement" $ do+ describe "validateChar" $ do+ it "lower" $ do+ let f x = CaseRefinement.validateChar x :: Maybe (ASCII'lower Int)+ f (-1) `shouldBe` Nothing+ f 65 `shouldBe` Nothing+ f 97 `shouldBe` Just (asciiCaseUnsafe 97)+ f 128 `shouldBe` Nothing - it "lower" $ do- let f x = CaseRefinement.toCaselessCharList (x :: ASCII'lower Text)- f (asciiCaseUnsafe "hi!") `shouldBe` [CC.LetterH, CC.LetterI, CC.ExclamationMark]+ it "upper" $ do+ let f x = CaseRefinement.validateChar x :: Maybe (ASCII'upper Int)+ f (-1) `shouldBe` Nothing+ f 65 `shouldBe` Just (asciiCaseUnsafe 65)+ f 97 `shouldBe` Nothing+ f 128 `shouldBe` Nothing - it "upper" $ do- let f x = CaseRefinement.toCaselessCharList (x :: ASCII'upper Text)- f (asciiCaseUnsafe "HI!") `shouldBe` [CC.LetterH, CC.LetterI, CC.ExclamationMark]+ describe "fromCaselessCharList" $ do+ it "lower" $ do+ let f x = CaseRefinement.fromCaselessCharList x :: ASCII'lower Text+ f [CC.LetterH, CC.LetterI, CC.ExclamationMark] `shouldBe` asciiCaseUnsafe "hi!" - describe "substituteString" $ do+ it "upper" $ do+ let f x = CaseRefinement.fromCaselessCharList x :: ASCII'upper Text+ f [CC.LetterH, CC.LetterI, CC.ExclamationMark] `shouldBe` asciiCaseUnsafe "HI!" - it "lower" $ do- let f x = CaseRefinement.substituteString x :: ASCII'lower Text- f "Cób" `shouldBe` asciiCaseUnsafe "\SUB\SUBb"+ describe "toCaselessCharList" $ do+ it "lower" $ do+ let f x = CaseRefinement.toCaselessCharList (x :: ASCII'lower Text)+ f (asciiCaseUnsafe "hi!") `shouldBe` [CC.LetterH, CC.LetterI, CC.ExclamationMark] - it "upper" $ do- let f x = CaseRefinement.substituteString x :: ASCII'upper Text- f "Cób" `shouldBe` asciiCaseUnsafe "C\SUB\SUB"+ it "upper" $ do+ let f x = CaseRefinement.toCaselessCharList (x :: ASCII'upper Text)+ f (asciiCaseUnsafe "HI!") `shouldBe` [CC.LetterH, CC.LetterI, CC.ExclamationMark] - describe "validateString" $ do+ describe "substituteString" $ do+ it "lower" $ do+ let f x = CaseRefinement.substituteString x :: ASCII'lower Text+ f "Cób" `shouldBe` asciiCaseUnsafe "\SUB\SUBb" - it "lower" $ do- let f x = CaseRefinement.validateString x :: Maybe (ASCII'lower Text)- f "hello" `shouldBe` Just (asciiCaseUnsafe "hello")- f "Hello" `shouldBe` Nothing+ it "upper" $ do+ let f x = CaseRefinement.substituteString x :: ASCII'upper Text+ f "Cób" `shouldBe` asciiCaseUnsafe "C\SUB\SUB" - it "upper" $ do- let f x = CaseRefinement.validateString x :: Maybe (ASCII'upper Text)- f "HELLO" `shouldBe` Just (asciiCaseUnsafe "HELLO")- f "Hello" `shouldBe` Nothing+ describe "validateString" $ do+ it "lower" $ do+ let f x = CaseRefinement.validateString x :: Maybe (ASCII'lower Text)+ f "hello" `shouldBe` Just (asciiCaseUnsafe "hello")+ f "Hello" `shouldBe` Nothing - describe "case conversion" $ do+ it "upper" $ do+ let f x = CaseRefinement.validateString x :: Maybe (ASCII'upper Text)+ f "HELLO" `shouldBe` Just (asciiCaseUnsafe "HELLO")+ f "Hello" `shouldBe` Nothing - describe "toCaseChar" $ do- let check :: forall a. Eq a => Superset.CharSuperset a => Expectation- check =- ([UpperCase, LowerCase] & Foldable.all (\c ->- ASCII.allCharacters & Foldable.all (\x ->- Superset.toCaseChar c (fromChar @a x)+ describe "case conversion" $ do+ describe "toCaseChar" $ do+ let check :: forall a. Eq a => Superset.CharSuperset a => Expectation+ check =+ ( [UpperCase, LowerCase]+ & Foldable.all+ ( \c ->+ ASCII.allCharacters+ & Foldable.all+ ( \x ->+ Superset.toCaseChar c (fromChar @a x) == fromChar @a (Case.toCase c x)- ))) `shouldBe` True- it "ASCII.Char" $ check @ASCII.Char- it "Unicode.Char" $ check @Unicode.Char- it "Natural" $ check @Natural- it "Int" $ check @Int- it "Word8" $ check @Word8-- describe "toCaseString" $ do- it "Text" $ do- let x = "012 abc DEF ﬓ" :: Text- Superset.toCaseString UpperCase x `shouldBe` "012 ABC DEF ﬓ"- Superset.toCaseString LowerCase x `shouldBe` "012 abc def ﬓ"-- describe "refineStringToCase" $ do- it "Text" $ do- let x = asciiUnsafe "Hi!" :: ASCII Text- CaseRefinement.refineStringToCase x `shouldBe` (asciiCaseUnsafe "HI!" :: ASCII'upper Text)- CaseRefinement.refineStringToCase x `shouldBe` (asciiCaseUnsafe "hi!" :: ASCII'lower Text)+ )+ )+ )+ `shouldBe` True+ it "ASCII.Char" $ check @ASCII.Char+ it "Unicode.Char" $ check @Unicode.Char+ it "Natural" $ check @Natural+ it "Int" $ check @Int+ it "Word8" $ check @Word8 - describe "toCasefulChar" $ do+ describe "toCaseString" $ do+ it "Text" $ do+ let x = "012 abc DEF ﬓ" :: Text+ Superset.toCaseString UpperCase x `shouldBe` "012 ABC DEF ﬓ"+ Superset.toCaseString LowerCase x `shouldBe` "012 abc def ﬓ" - describe "lower case" $ do- let a :: Superset.ToCasefulChar 'LowerCase char => char- a = Superset.toCasefulChar @'LowerCase CC.LetterA+ describe "refineStringToCase" $ do+ it "Text" $ do+ let x = asciiUnsafe "Hi!" :: ASCII Text+ CaseRefinement.refineStringToCase x `shouldBe` (asciiCaseUnsafe "HI!" :: ASCII'upper Text)+ CaseRefinement.refineStringToCase x `shouldBe` (asciiCaseUnsafe "hi!" :: ASCII'lower Text) - it "can be Char" $ a `shouldBe` SmallLetterA- it "can be superset type" $ a `shouldBe` 'a'- it "can be case-refined type" $ a `shouldBe` (asciiCaseUnsafe 'a' :: ASCII'lower Unicode.Char)+ describe "toCasefulChar" $ do+ describe "lower case" $ do+ let a :: Superset.ToCasefulChar 'LowerCase char => char+ a = Superset.toCasefulChar @'LowerCase CC.LetterA - describe "upper case" $ do- let a :: Superset.ToCasefulChar 'UpperCase char => char- a = Superset.toCasefulChar @'UpperCase CC.LetterA+ it "can be Char" $ a `shouldBe` SmallLetterA+ it "can be superset type" $ a `shouldBe` 'a'+ it "can be case-refined type" $ a `shouldBe` (asciiCaseUnsafe 'a' :: ASCII'lower Unicode.Char) - it "can be Char" $ a `shouldBe` CapitalLetterA- it "can be superset type" $ a `shouldBe` 'A'- it "can be case-refined type" $ a `shouldBe` (asciiCaseUnsafe 'A' :: ASCII'upper Unicode.Char)+ describe "upper case" $ do+ let a :: Superset.ToCasefulChar 'UpperCase char => char+ a = Superset.toCasefulChar @'UpperCase CC.LetterA - describe "toCasefulString" $ do+ it "can be Char" $ a `shouldBe` CapitalLetterA+ it "can be superset type" $ a `shouldBe` 'A'+ it "can be case-refined type" $ a `shouldBe` (asciiCaseUnsafe 'A' :: ASCII'upper Unicode.Char) - describe "lower case" $ do- let x :: Superset.ToCasefulString 'LowerCase string => string- x = Superset.toCasefulString @'LowerCase [CC.LetterH, CC.LetterI, CC.ExclamationMark]+ describe "toCasefulString" $ do+ describe "lower case" $ do+ let x :: Superset.ToCasefulString 'LowerCase string => string+ x = Superset.toCasefulString @'LowerCase [CC.LetterH, CC.LetterI, CC.ExclamationMark] - it "can be [Char]" $ x `shouldBe` [SmallLetterH, SmallLetterI, ExclamationMark]- it "can be superset type" $ x `shouldBe` ("hi!" :: Text)- it "can be case-refined type" $ x `shouldBe` (asciiCaseUnsafe "hi!" :: ASCII'lower Text)+ it "can be [Char]" $ x `shouldBe` [SmallLetterH, SmallLetterI, ExclamationMark]+ it "can be superset type" $ x `shouldBe` ("hi!" :: Text)+ it "can be case-refined type" $ x `shouldBe` (asciiCaseUnsafe "hi!" :: ASCII'lower Text) - describe "upper case" $ do- let x :: Superset.ToCasefulString 'UpperCase string => string- x = Superset.toCasefulString @'UpperCase [CC.LetterH, CC.LetterI, CC.ExclamationMark]+ describe "upper case" $ do+ let x :: Superset.ToCasefulString 'UpperCase string => string+ x = Superset.toCasefulString @'UpperCase [CC.LetterH, CC.LetterI, CC.ExclamationMark] - it "can be [Char]" $ x `shouldBe` [CapitalLetterH, CapitalLetterI, ExclamationMark]- it "can be superset type" $ x `shouldBe` ("HI!" :: Text)- it "can be case-refined type" $ x `shouldBe` (asciiCaseUnsafe "HI!" :: ASCII'upper Text)+ it "can be [Char]" $ x `shouldBe` [CapitalLetterH, CapitalLetterI, ExclamationMark]+ it "can be superset type" $ x `shouldBe` ("HI!" :: Text)+ it "can be case-refined type" $ x `shouldBe` (asciiCaseUnsafe "HI!" :: ASCII'upper Text)