packages feed

ascii-superset (empty) → 1.0.0.0

raw patch · 6 files changed

+477/−0 lines, 6 filesdep +ascii-chardep +basedep +bytestring

Dependencies added: ascii-char, base, bytestring, hashable, text

Files

+ ASCII/Isomorphism.hs view
@@ -0,0 +1,28 @@+module ASCII.Isomorphism ( CharIso (..), asChar, StringIso (..) ) where++import ASCII.Char     ( Char )+import ASCII.Superset ( CharSuperset (..), StringSuperset (..) )+import Data.Function  ( id, (.) )+import Data.List      ( map )++class CharSuperset char => 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++-- | 'Char' is trivially isomorphic to itself.+instance CharIso Char+  where+    toChar = id++instance CharIso char => StringIso [char]+  where+    toCharList = map toChar+    mapChars f = map (asChar f)
+ ASCII/Lift.hs view
@@ -0,0 +1,47 @@+{-# LANGUAGE FlexibleInstances, MultiParamTypeClasses #-}++module ASCII.Lift ( Lift (..) ) where++import ASCII.Char       ( Char )+import ASCII.Refinement ( ASCII )+import ASCII.Superset   ( CharSuperset, StringSuperset )++import qualified ASCII.Refinement as R+import qualified ASCII.Superset as S++{- $setup++>>> import ASCII.Char (Char (..))+>>> import Data.Text (Text)+>>> import Data.Word (Word8)++-}++class Lift ascii superset+  where++    {- | Converts from ASCII to any larger type.++    >>> lift CapitalLetterA :: Word8+    65++    >>> lift [CapitalLetterH,SmallLetterI,ExclamationMark] :: Text+    "Hi!"++    Due to the highly polymorphic nature of the 'lift' function, often it must used with an explicit type signature or type application to avoid any type ambiguity.++    -}++    lift :: ascii -> superset++-- | A value from an ASCII superset that has been refined by the 'ASCII' type constructor may be lifted back into the superset by unwrapping it from the 'ASCII' type.++instance Lift (ASCII superset) superset where lift = R.lift++-- | An ASCII 'Char' may be 'lift'ed into any larger character set (a 'CharSuperset').++instance CharSuperset superset => Lift Char superset where lift = S.fromChar++-- | An ASCII 'Char' list may be 'lift'ed into a string of any larger character set (a 'StringSuperset').++instance StringSuperset superset => Lift [Char] superset where lift = S.fromCharList
+ ASCII/Refinement.hs view
@@ -0,0 +1,161 @@+module ASCII.Refinement+  (+    {- * ASCII type constructor -} ASCII, lift, asciiUnsafe,+    {- * Character functions -} validateChar, fromChar, toChar, substituteChar, asChar,+    {- * String functions -} validateString, fromCharList, toCharList, substituteString, mapChars+  )+  where++import qualified ASCII.Char as ASCII+import qualified ASCII.Superset as S+import qualified ASCII.Isomorphism as I++import ASCII.Superset    ( CharSuperset, StringSuperset )+import Data.Bool         ( Bool (..) )+import Data.Data         ( Data )+import Data.Eq           ( Eq )+import Data.Function     ( (.), ($), id )+import Data.Hashable     ( Hashable )+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 Prelude           ( succ )+import Text.Show         ( Show, showString, showsPrec, showParen, showList )++{- $setup++>>> :set -XOverloadedStrings+>>> import ASCII.Char (Char (..))+>>> import Data.List (map)+>>> import Data.Int (Int)+>>> import Data.String (String)+>>> import Data.Text (Text)++-}++{- | 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 }++deriving stock instance Eq superset => Eq (ASCII superset)++deriving stock instance Ord superset => Ord (ASCII superset)++deriving newtype instance Hashable superset => Hashable (ASCII superset)++deriving newtype instance Semigroup superset => Semigroup (ASCII superset)++deriving newtype instance Monoid superset => Monoid (ASCII superset)++deriving stock instance Data superset => Data (ASCII superset)++deriving stock instance Generic (ASCII superset)++instance Show superset => Show (ASCII superset)+  where+    showsPrec d x = showParen (d > app_prec) $+        showString "asciiUnsafe " . showsPrec (succ app_prec) (lift x)+      where app_prec = 10++    showList x = showString "asciiUnsafe " . showList (map lift x)++instance CharSuperset char => CharSuperset (ASCII char)+  where+    isAsciiChar _ = True+    fromChar = asciiUnsafe . S.fromChar+    toCharUnsafe = S.toCharUnsafe . lift++instance CharSuperset char => I.CharIso (ASCII char)+  where+    toChar = S.toCharUnsafe++instance StringSuperset string => StringSuperset (ASCII string)+  where+    isAsciiString _ = True+    fromCharList = asciiUnsafe . S.fromCharList+    toCharListUnsafe = S.toCharListUnsafe . lift+    toCharListSub = S.toCharListUnsafe . lift+    substituteString = id++instance StringSuperset string => I.StringIso (ASCII string)+  where+    toCharList = S.toCharListUnsafe+    mapChars = S.mapCharsUnsafe++asciiUnsafe :: superset -> ASCII superset+asciiUnsafe = ASCII_Unsafe++{- |++>>> map validateChar [-1, 65, 97, 128] :: [Maybe (ASCII Int)]+[Nothing,Just (asciiUnsafe 65),Just (asciiUnsafe 97),Nothing]++-}++validateChar :: CharSuperset superset => superset -> Maybe (ASCII superset)+validateChar x = if S.isAsciiChar x then Just (asciiUnsafe x) else Nothing++substituteChar :: CharSuperset superset => superset -> ASCII superset+substituteChar x = if S.isAsciiChar x then asciiUnsafe x else fromChar ASCII.Substitute++fromChar :: CharSuperset superset => ASCII.Char -> ASCII superset+fromChar = asciiUnsafe . S.fromChar++toChar :: CharSuperset superset => ASCII superset -> ASCII.Char+toChar = S.toCharUnsafe . lift++{- |++>>> fromCharList [CapitalLetterH,SmallLetterI,ExclamationMark] :: ASCII Text+asciiUnsafe "Hi!"++-}++fromCharList :: StringSuperset superset => [ASCII.Char] -> ASCII superset+fromCharList = asciiUnsafe . S.fromCharList++{- |++>>> toCharList (substituteString "Piñata" :: ASCII Text)+[CapitalLetterP,SmallLetterI,Substitute,SmallLetterA,SmallLetterT,SmallLetterA]++-}++toCharList :: 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"++-}++substituteString :: 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]++-}++validateString :: StringSuperset superset => superset -> Maybe (ASCII superset)+validateString x = if S.isAsciiString x then Just (asciiUnsafe x) else Nothing++asChar :: CharSuperset superset => (ASCII.Char -> ASCII.Char) -> ASCII superset -> ASCII superset+asChar f = asciiUnsafe . S.asCharUnsafe f . lift++mapChars :: StringSuperset superset => (ASCII.Char -> ASCII.Char) -> ASCII superset -> ASCII superset+mapChars f = asciiUnsafe . S.mapCharsUnsafe f . lift
+ ASCII/Superset.hs view
@@ -0,0 +1,182 @@+module ASCII.Superset (++    {- * Characters -}+    {- ** Class -} CharSuperset (..),+    {- ** Functions -} asCharUnsafe, toCharMaybe, toCharOrFail, toCharSub, substituteChar,++    {- * Strings -}+    {- ** Class -} StringSuperset (..),+    {- ** Functions -} toCharListMaybe, toCharListOrFail++    ) where++import Control.Monad      ( return )+import Control.Monad.Fail ( MonadFail (fail) )+import Data.Bool          ( Bool, (&&) )+import Data.Function      ( (.), id )+import Data.Ord           ( (<=), (>=) )+import Data.Maybe         ( Maybe (..) )++import qualified ASCII.Char               as  ASCII+import qualified Data.Bool                as  Bool+import qualified Data.ByteString          as  BS+import qualified Data.ByteString.Lazy     as  LBS+import qualified Data.ByteString.Builder  as  BSB+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+++---  Char  ---++class CharSuperset char+  where++    isAsciiChar :: char -> Bool++    fromChar :: ASCII.Char -> char++    toCharUnsafe :: char -> ASCII.Char++asCharUnsafe :: CharSuperset char => (ASCII.Char -> ASCII.Char) -> char -> char+asCharUnsafe f = fromChar . f . toCharUnsafe++toCharMaybe :: CharSuperset char => char -> Maybe ASCII.Char+toCharMaybe = toCharOrFail++toCharOrFail :: (CharSuperset char, MonadFail context) => char -> context ASCII.Char+toCharOrFail x = if isAsciiChar x then return (toCharUnsafe x) else fail "Not an ASCII character"++toCharSub :: CharSuperset char => char -> ASCII.Char+toCharSub x = if isAsciiChar x then toCharUnsafe x else ASCII.Substitute++substituteChar :: CharSuperset char => char -> char+substituteChar x = if isAsciiChar x then x else fromChar ASCII.Substitute+++---  String  ---++class StringSuperset string+  where++    isAsciiString :: string -> Bool++    fromCharList :: [ASCII.Char] -> string++    toCharListUnsafe :: string -> [ASCII.Char]++    toCharListSub :: string -> [ASCII.Char]++    substituteString :: string -> string++    mapCharsUnsafe :: (ASCII.Char -> ASCII.Char) -> string -> string+    mapCharsUnsafe f = fromCharList  . List.map f . toCharListUnsafe++toCharListMaybe :: StringSuperset string => string -> Maybe [ASCII.Char]+toCharListMaybe = toCharListOrFail++toCharListOrFail :: (StringSuperset string, MonadFail context) => string -> context [ASCII.Char]+toCharListOrFail x = if isAsciiString x then return (toCharListUnsafe x) else fail "String contains non-ASCII characters"+++---  Instances  ---++-- | 'ASCII.Char' is trivially a superset of itself.++instance CharSuperset ASCII.Char+  where+    isAsciiChar _ = Bool.True+    fromChar = id+    toCharUnsafe = id++instance CharSuperset Unicode.Char+  where+    isAsciiChar = (<= '\DEL')+    fromChar = Unicode.chr . ASCII.toInt+    toCharUnsafe = ASCII.fromIntUnsafe . Unicode.ord++instance CharSuperset Nat.Natural+  where+    isAsciiChar = (<= 127)+    fromChar = Prelude.fromIntegral . ASCII.toInt+    toCharUnsafe = ASCII.fromIntUnsafe . Prelude.fromIntegral++instance CharSuperset Int.Int+  where+    isAsciiChar x = (x >= 0) && (x <= 127)+    fromChar = ASCII.toInt+    toCharUnsafe = ASCII.fromIntUnsafe++instance CharSuperset Word.Word8+  where+    isAsciiChar = (<= 127)+    fromChar = Prelude.fromIntegral . ASCII.toInt+    toCharUnsafe = ASCII.fromIntUnsafe . Prelude.fromIntegral++instance CharSuperset char => StringSuperset [char]+  where+    isAsciiString = List.all isAsciiChar+    fromCharList = List.map fromChar+    toCharListUnsafe = List.map toCharUnsafe+    toCharListSub = List.map toCharSub+    substituteString = List.map substituteChar++instance StringSuperset T.Text+  where+    isAsciiString = T.all isAsciiChar+    fromCharList = T.pack . fromCharList+    toCharListUnsafe = toCharListUnsafe . T.unpack+    toCharListSub = toCharListSub . T.unpack+    substituteString = T.map substituteChar+    mapCharsUnsafe f = T.map (asCharUnsafe f)++instance StringSuperset LT.Text+  where+    isAsciiString = LT.all isAsciiChar+    fromCharList = LT.pack . fromCharList+    toCharListUnsafe = toCharListUnsafe . LT.unpack+    toCharListSub = toCharListSub . LT.unpack+    substituteString = LT.map substituteChar+    mapCharsUnsafe f = LT.map (asCharUnsafe f)++instance StringSuperset TB.Builder+  where+    isAsciiString = isAsciiString . TB.toLazyText+    fromCharList = TB.fromString . fromCharList+    toCharListUnsafe = toCharListUnsafe . TB.toLazyText+    toCharListSub = toCharListSub . TB.toLazyText+    substituteString = TB.fromLazyText . substituteString . TB.toLazyText+    mapCharsUnsafe f = TB.fromLazyText . mapCharsUnsafe f . TB.toLazyText++instance StringSuperset BS.ByteString+  where+    isAsciiString = BS.all isAsciiChar+    fromCharList = BS.pack . fromCharList+    toCharListUnsafe = toCharListUnsafe . BS.unpack+    toCharListSub = toCharListSub . BS.unpack+    substituteString = BS.map substituteChar+    mapCharsUnsafe f = BS.map (asCharUnsafe f)++instance StringSuperset LBS.ByteString+  where+    isAsciiString = LBS.all isAsciiChar+    fromCharList = LBS.pack . fromCharList+    toCharListUnsafe = toCharListUnsafe . LBS.unpack+    toCharListSub = toCharListSub . LBS.unpack+    substituteString = LBS.map substituteChar+    mapCharsUnsafe f = LBS.map (asCharUnsafe f)++instance StringSuperset BSB.Builder+  where+    isAsciiString = isAsciiString . BSB.toLazyByteString+    fromCharList = BSB.lazyByteString . fromCharList+    toCharListUnsafe = toCharListUnsafe . BSB.toLazyByteString+    toCharListSub = toCharListSub . BSB.toLazyByteString+    substituteString = BSB.lazyByteString . substituteString . BSB.toLazyByteString+    mapCharsUnsafe f = BSB.lazyByteString . mapCharsUnsafe f . BSB.toLazyByteString
+ ascii-superset.cabal view
@@ -0,0 +1,46 @@+cabal-version: 2.0++name: ascii-superset+version: 1.0.0.0+synopsis: Representing ASCII with refined supersets+category: Data, Text++description: This package defines classes which describe what subset of a type is valid as ASCII, as well as a type constructor representing a value of a superset that is known to be valid ASCII.++license: Apache-2.0+license-file: license.txt++author: Chris Martin+maintainer: Chris Martin, Julie Moronuki++homepage:    https://github.com/typeclasses/ascii+bug-Reports: https://github.com/typeclasses/ascii/issues++build-type: Simple++tested-with: GHC == 8.8.1, GHC == 8.6.5, GHC == 8.4.3++source-repository head+    type:     git+    location: git://github.com/typeclasses/ascii.git++library+    default-language: Haskell2010+    default-extensions: NoImplicitPrelude+    default-extensions: StandaloneDeriving+    default-extensions: DerivingStrategies+    default-extensions: GeneralizedNewtypeDeriving+    default-extensions: DeriveDataTypeable+    default-extensions: DeriveGeneric+    ghc-options: -Wall++    build-depends: base       >= 4.11 && < 4.14+    build-depends: bytestring >= 0.10 && < 0.11+    build-depends: ascii-char >= 1.0  && < 1.1+    build-depends: hashable   >= 1.2  && < 1.4+    build-depends: text       >= 1.2  && < 1.3++    exposed-modules: ASCII.Superset+    exposed-modules: ASCII.Isomorphism+    exposed-modules: ASCII.Refinement+    exposed-modules: ASCII.Lift
+ license.txt view
@@ -0,0 +1,13 @@+Copyright 2020 Typeclass Consulting LLC++Licensed under the Apache License, Version 2.0 (the "License");+you may not use this file except in compliance with the License.+You may obtain a copy of the License at++    http://www.apache.org/licenses/LICENSE-2.0++Unless required by applicable law or agreed to in writing, software+distributed under the License is distributed on an "AS IS" BASIS,+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.+See the License for the specific language governing permissions and+limitations under the License.