packages feed

kleene 0.1 → 0.2

raw patch · 17 files changed

+372/−226 lines, 17 filesdep +kleenedep +tastydep +tasty-hunitdep −attoparsecdep −base-compatdep −semigroupsdep ~QuickCheckdep ~basedep ~bytestringPVP ok

version bump matches the API change (PVP)

Dependencies added: kleene, tasty, tasty-hunit, tasty-quickcheck

Dependencies removed: attoparsec, base-compat, semigroups, text, transformers

Dependency ranges changed: QuickCheck, base, bytestring, containers, regex-applicative, step-function

API changes (from Hackage documentation)

- Kleene.ERE: instance (c Data.Type.Equality.~ GHC.Types.Char) => Data.String.IsString (Kleene.ERE.ERE c)
- Kleene.ERE: instance (c Data.Type.Equality.~ GHC.Types.Char) => Kleene.Internal.Pretty.Pretty (Kleene.ERE.ERE c)
- Kleene.Functor.NonEmpty: instance (c Data.Type.Equality.~ GHC.Types.Char) => Kleene.Internal.Pretty.Pretty (Kleene.Functor.NonEmpty.K1 c a)
- Kleene.Internal.Pretty: instance (c Data.Type.Equality.~ GHC.Types.Char) => Kleene.Internal.Pretty.Pretty (Data.RangeSet.Map.RSet c)
- Kleene.Monad: MChars :: [c] -> M c
- Kleene.Monad: instance (c Data.Type.Equality.~ GHC.Types.Char) => Data.String.IsString (Kleene.Monad.M c)
+ Kleene: ($dmnotChar) :: (FiniteKleene c k, Ord c, Enum c, Bounded c) => c -> k
+ Kleene: class Match c k => Equivalent c k | k -> c
+ Kleene: equivalent :: Equivalent c k => k -> k -> Bool
+ Kleene.Classes: ($dmnotChar) :: (FiniteKleene c k, Ord c, Enum c, Bounded c) => c -> k
+ Kleene.ERE: everything :: ERE c
+ Kleene.ERE: instance (c GHC.Types.~ GHC.Types.Char) => Data.String.IsString (Kleene.ERE.ERE c)
+ Kleene.ERE: instance (c GHC.Types.~ GHC.Types.Char) => Kleene.Internal.Pretty.Pretty (Kleene.ERE.ERE c)
+ Kleene.Functor.NonEmpty: few1 :: K1 c a -> K1 c (NonEmpty a)
+ Kleene.Functor.NonEmpty: instance (c GHC.Types.~ GHC.Types.Char) => Kleene.Internal.Pretty.Pretty (Kleene.Functor.NonEmpty.K1 c a)
+ Kleene.Internal.Functor: Greedy :: Greediness
+ Kleene.Internal.Functor: NonGreedy :: Greediness
+ Kleene.Internal.Functor: [KAppend] :: forall a1 b a c. (a1 -> b -> a) -> K c a1 -> K c b -> K c a
+ Kleene.Internal.Functor: [KChar] :: forall c. (Ord c, Enum c) => RSet c -> K c c
+ Kleene.Internal.Functor: [KEmpty] :: forall c a. K c a
+ Kleene.Internal.Functor: [KMap] :: forall a1 a c. (a1 -> a) -> K c a1 -> K c a
+ Kleene.Internal.Functor: [KPure] :: forall a c. a -> K c a
+ Kleene.Internal.Functor: [KStar] :: forall c a1. Greediness -> K c a1 -> K c [a1]
+ Kleene.Internal.Functor: [KString] :: forall c. Eq c => [c] -> K c [c]
+ Kleene.Internal.Functor: [KUnion] :: forall c a. K c a -> K c a -> K c a
+ Kleene.Internal.Functor: anyChar :: (Ord c, Enum c, Bounded c) => K c c
+ Kleene.Internal.Functor: char :: (Ord c, Enum c) => c -> K c c
+ Kleene.Internal.Functor: charRange :: (Enum c, Ord c) => c -> c -> K c c
+ Kleene.Internal.Functor: data Greediness
+ Kleene.Internal.Functor: data K c a
+ Kleene.Internal.Functor: dot :: K Char Char
+ Kleene.Internal.Functor: everything :: (Ord c, Enum c, Bounded c) => K c [c]
+ Kleene.Internal.Functor: everything1 :: (Ord c, Enum c, Bounded c) => K c [c]
+ Kleene.Internal.Functor: few :: K c a -> K c [a]
+ Kleene.Internal.Functor: fromRE :: (Ord c, Enum c) => RE c -> K c [c]
+ Kleene.Internal.Functor: instance (c GHC.Types.~ GHC.Types.Char) => Kleene.Internal.Pretty.Pretty (Kleene.Internal.Functor.K c a)
+ Kleene.Internal.Functor: instance (c GHC.Types.~ GHC.Types.Char, Data.String.IsString a) => Data.String.IsString (Kleene.Internal.Functor.K c a)
+ Kleene.Internal.Functor: instance Data.Functor.Alt.Alt (Kleene.Internal.Functor.K c)
+ Kleene.Internal.Functor: instance Data.Functor.Bind.Class.Apply (Kleene.Internal.Functor.K c)
+ Kleene.Internal.Functor: instance GHC.Base.Alternative (Kleene.Internal.Functor.K c)
+ Kleene.Internal.Functor: instance GHC.Base.Applicative (Kleene.Internal.Functor.K c)
+ Kleene.Internal.Functor: instance GHC.Base.Functor (Kleene.Internal.Functor.K c)
+ Kleene.Internal.Functor: instance GHC.Classes.Eq Kleene.Internal.Functor.Greediness
+ Kleene.Internal.Functor: instance GHC.Classes.Ord Kleene.Internal.Functor.Greediness
+ Kleene.Internal.Functor: instance GHC.Enum.Bounded Kleene.Internal.Functor.Greediness
+ Kleene.Internal.Functor: instance GHC.Enum.Enum Kleene.Internal.Functor.Greediness
+ Kleene.Internal.Functor: instance GHC.Show.Show Kleene.Internal.Functor.Greediness
+ Kleene.Internal.Functor: isEmpty :: (Ord c, Enum c, Bounded c) => K c a -> Bool
+ Kleene.Internal.Functor: isEverything :: (Ord c, Enum c, Bounded c) => K c a -> Bool
+ Kleene.Internal.Functor: match :: K c a -> [c] -> Maybe a
+ Kleene.Internal.Functor: oneof :: (Ord c, Enum c, Foldable f) => f c -> K c c
+ Kleene.Internal.Functor: toKleene :: FiniteKleene c k => K c a -> k
+ Kleene.Internal.Functor: toRA :: K c a -> RE c a
+ Kleene.Internal.Functor: toRE :: (Ord c, Enum c, Bounded c) => K c a -> RE c
+ Kleene.Internal.Pretty: instance (c GHC.Types.~ GHC.Types.Char) => Kleene.Internal.Pretty.Pretty (Data.RangeSet.Map.RSet c)
+ Kleene.Internal.RE: REAppend :: [RE c] -> RE c
+ Kleene.Internal.RE: REChars :: RSet c -> RE c
+ Kleene.Internal.RE: REStar :: RE c -> RE c
+ Kleene.Internal.RE: REUnion :: RSet c -> Set (RE c) -> RE c
+ Kleene.Internal.RE: anyChar :: Bounded c => RE c
+ Kleene.Internal.RE: appends :: Eq c => [RE c] -> RE c
+ Kleene.Internal.RE: char :: c -> RE c
+ Kleene.Internal.RE: charRange :: Ord c => c -> c -> RE c
+ Kleene.Internal.RE: data RE c
+ Kleene.Internal.RE: derivate :: (Ord c, Enum c, Bounded c) => c -> RE c -> RE c
+ Kleene.Internal.RE: empty :: RE c
+ Kleene.Internal.RE: eps :: RE c
+ Kleene.Internal.RE: equivalent :: (Ord c, Enum c, Bounded c) => RE c -> RE c -> Bool
+ Kleene.Internal.RE: everything :: Bounded c => RE c
+ Kleene.Internal.RE: generate :: (c -> c -> Gen c) -> Int -> RE c -> [[c]]
+ Kleene.Internal.RE: instance (GHC.Classes.Ord c, GHC.Enum.Enum c, GHC.Enum.Bounded c) => Kleene.Classes.CharKleene c (Kleene.Internal.RE.RE c)
+ Kleene.Internal.RE: instance (GHC.Classes.Ord c, GHC.Enum.Enum c, GHC.Enum.Bounded c) => Kleene.Classes.Derivate c (Kleene.Internal.RE.RE c)
+ Kleene.Internal.RE: instance (GHC.Classes.Ord c, GHC.Enum.Enum c, GHC.Enum.Bounded c) => Kleene.Classes.Equivalent c (Kleene.Internal.RE.RE c)
+ Kleene.Internal.RE: instance (GHC.Classes.Ord c, GHC.Enum.Enum c, GHC.Enum.Bounded c) => Kleene.Classes.FiniteKleene c (Kleene.Internal.RE.RE c)
+ Kleene.Internal.RE: instance (GHC.Classes.Ord c, GHC.Enum.Enum c, GHC.Enum.Bounded c) => Kleene.Classes.Kleene (Kleene.Internal.RE.RE c)
+ Kleene.Internal.RE: instance (GHC.Classes.Ord c, GHC.Enum.Enum c, GHC.Enum.Bounded c) => Kleene.Classes.Match c (Kleene.Internal.RE.RE c)
+ Kleene.Internal.RE: instance (GHC.Classes.Ord c, GHC.Enum.Enum c, GHC.Enum.Bounded c) => Kleene.Classes.TransitionMap c (Kleene.Internal.RE.RE c)
+ Kleene.Internal.RE: instance (GHC.Classes.Ord c, GHC.Enum.Enum c, GHC.Enum.Bounded c, Test.QuickCheck.Arbitrary.Arbitrary c) => Test.QuickCheck.Arbitrary.Arbitrary (Kleene.Internal.RE.RE c)
+ Kleene.Internal.RE: instance (c GHC.Types.~ GHC.Types.Char) => Data.String.IsString (Kleene.Internal.RE.RE c)
+ Kleene.Internal.RE: instance (c GHC.Types.~ GHC.Types.Char) => Kleene.Internal.Pretty.Pretty (Kleene.Internal.RE.RE c)
+ Kleene.Internal.RE: instance GHC.Classes.Eq c => GHC.Base.Monoid (Kleene.Internal.RE.RE c)
+ Kleene.Internal.RE: instance GHC.Classes.Eq c => GHC.Base.Semigroup (Kleene.Internal.RE.RE c)
+ Kleene.Internal.RE: instance GHC.Classes.Eq c => GHC.Classes.Eq (Kleene.Internal.RE.RE c)
+ Kleene.Internal.RE: instance GHC.Classes.Ord c => GHC.Classes.Ord (Kleene.Internal.RE.RE c)
+ Kleene.Internal.RE: instance GHC.Show.Show c => GHC.Show.Show (Kleene.Internal.RE.RE c)
+ Kleene.Internal.RE: instance Kleene.Classes.ToLatin1 Kleene.Internal.RE.RE
+ Kleene.Internal.RE: instance Test.QuickCheck.Arbitrary.CoArbitrary c => Test.QuickCheck.Arbitrary.CoArbitrary (Kleene.Internal.RE.RE c)
+ Kleene.Internal.RE: isEmpty :: RE c -> Bool
+ Kleene.Internal.RE: leadingChars :: (Ord c, Enum c, Bounded c) => RE c -> Partition c
+ Kleene.Internal.RE: nullable :: RE c -> Bool
+ Kleene.Internal.RE: nullableProof :: (Ord c, Enum c, Bounded c) => RE c -> Maybe (RE c)
+ Kleene.Internal.RE: star :: Ord c => RE c -> RE c
+ Kleene.Internal.RE: string :: [c] -> RE c
+ Kleene.Internal.RE: transitionMap :: (Ord c, Enum c, Bounded c) => RE c -> Map (RE c) (SF c (RE c))
+ Kleene.Internal.RE: unions :: (Ord c, Enum c, Bounded c) => [RE c] -> RE c
+ Kleene.Monad: instance (c GHC.Types.~ GHC.Types.Char) => Data.String.IsString (Kleene.Monad.M c)
+ Kleene.RE: everything :: Bounded c => RE c
- Kleene: Equiv :: r c -> Equiv r c
+ Kleene: Equiv :: r c -> Equiv (r :: Type -> Type) c
- Kleene: class ToLatin1 k
+ Kleene: class ToLatin1 (k :: Type -> Type)
- Kleene: dot :: (FiniteKleene c k, c ~ Char) => k
+ Kleene: dot :: FiniteKleene c k => k
- Kleene: fromTM :: forall k c. (Ord k, Ord c, TransitionMap c k) => k -> DFA c
+ Kleene: fromTM :: (Ord k, Ord c, TransitionMap c k) => k -> DFA c
- Kleene: fromTMEquiv :: forall k c. (Ord k, Ord c, TransitionMap c k, Equivalent c k) => k -> DFA c
+ Kleene: fromTMEquiv :: (Ord k, Ord c, TransitionMap c k, Equivalent c k) => k -> DFA c
- Kleene: match8 :: (Match c k, c ~ Word8) => k -> ByteString -> Bool
+ Kleene: match8 :: Match c k => k -> ByteString -> Bool
- Kleene: newtype Equiv r c
+ Kleene: newtype Equiv (r :: Type -> Type) c
- Kleene: notChar :: (FiniteKleene c k, Ord c, Enum c, Bounded c) => c -> k
+ Kleene: notChar :: FiniteKleene c k => c -> k
- Kleene.Classes: class ToLatin1 k
+ Kleene.Classes: class ToLatin1 (k :: Type -> Type)
- Kleene.Classes: dot :: (FiniteKleene c k, c ~ Char) => k
+ Kleene.Classes: dot :: FiniteKleene c k => k
- Kleene.Classes: match8 :: (Match c k, c ~ Word8) => k -> ByteString -> Bool
+ Kleene.Classes: match8 :: Match c k => k -> ByteString -> Bool
- Kleene.Classes: notChar :: (FiniteKleene c k, Ord c, Enum c, Bounded c) => c -> k
+ Kleene.Classes: notChar :: FiniteKleene c k => c -> k
- Kleene.DFA: fromERE :: forall c. (Ord c, Enum c, Bounded c) => ERE c -> DFA c
+ Kleene.DFA: fromERE :: (Ord c, Enum c, Bounded c) => ERE c -> DFA c
- Kleene.DFA: fromRE :: forall c. (Ord c, Enum c, Bounded c) => RE c -> DFA c
+ Kleene.DFA: fromRE :: (Ord c, Enum c, Bounded c) => RE c -> DFA c
- Kleene.DFA: fromTM :: forall k c. (Ord k, Ord c, TransitionMap c k) => k -> DFA c
+ Kleene.DFA: fromTM :: (Ord k, Ord c, TransitionMap c k) => k -> DFA c
- Kleene.DFA: fromTMEquiv :: forall k c. (Ord k, Ord c, TransitionMap c k, Equivalent c k) => k -> DFA c
+ Kleene.DFA: fromTMEquiv :: (Ord k, Ord c, TransitionMap c k, Equivalent c k) => k -> DFA c
- Kleene.ERE: equivalent :: forall c. (Ord c, Enum c, Bounded c) => ERE c -> ERE c -> Bool
+ Kleene.ERE: equivalent :: (Ord c, Enum c, Bounded c) => ERE c -> ERE c -> Bool
- Kleene.ERE: transitionMap :: forall c. (Ord c, Enum c, Bounded c) => ERE c -> Map (ERE c) (SF c (ERE c))
+ Kleene.ERE: transitionMap :: (Ord c, Enum c, Bounded c) => ERE c -> Map (ERE c) (SF c (ERE c))
- Kleene.Equiv: Equiv :: r c -> Equiv r c
+ Kleene.Equiv: Equiv :: r c -> Equiv (r :: Type -> Type) c
- Kleene.Equiv: newtype Equiv r c
+ Kleene.Equiv: newtype Equiv (r :: Type -> Type) c
- Kleene.RE: equivalent :: forall c. (Ord c, Enum c, Bounded c) => RE c -> RE c -> Bool
+ Kleene.RE: equivalent :: (Ord c, Enum c, Bounded c) => RE c -> RE c -> Bool
- Kleene.RE: nullableProof :: forall c. (Ord c, Enum c, Bounded c) => RE c -> Maybe (RE c)
+ Kleene.RE: nullableProof :: (Ord c, Enum c, Bounded c) => RE c -> Maybe (RE c)
- Kleene.RE: transitionMap :: forall c. (Ord c, Enum c, Bounded c) => RE c -> Map (RE c) (SF c (RE c))
+ Kleene.RE: transitionMap :: (Ord c, Enum c, Bounded c) => RE c -> Map (RE c) (SF c (RE c))

Files

CHANGELOG.md view
@@ -1,3 +1,13 @@+## 0.2++* Remove MChars constructor from Monad variant++## 0.1.1++* Export `Kleene.Functor.NonEmpty.few1`+* Export `Kleene.RE.everything` and `Kleene.ERE.everything`+* Export `Equivalent` from `Kleene`+ ## 0.1  * Drop superclasses from `Kleene`.
kleene.cabal view
@@ -1,6 +1,6 @@-cabal-version:      1.24+cabal-version:      2.4 name:               kleene-version:            0.1+version:            0.2 synopsis:           Kleene algebra category:           Math description:@@ -16,41 +16,48 @@ bug-reports:        https://github.com/phadej/kleene/issues author:             Oleg Grenrus <oleg.grenrus@iki.fi> maintainer:         Oleg Grenrus <oleg.grenrus@iki.fi>-license:            BSD3+license:            BSD-3-Clause license-file:       LICENSE build-type:         Simple extra-source-files: CHANGELOG.md extra-doc-files:    example.png tested-with:-  GHC ==7.8.4 || ==7.10.3 || ==8.0.2 || ==8.2.2 || ==8.4.4 || ==8.6.5 || ==8.8.1+  GHC ==8.6.5+   || ==8.8.4+   || ==8.10.7+   || ==9.0.2+   || ==9.2.8+   || ==9.4.8+   || ==9.6.7+   || ==9.8.4+   || ==9.10.3+   || ==9.12.4+   || ==9.14.1  source-repository head   type:     git   location: https://github.com/phadej/kleene  library+  default-language:  Haskell2010+  ghc-options:       -Wall+  hs-source-dirs:    src+   -- GHC boot libraries   build-depends:-      base          >=4.7.0.2  && <4.13-    , bytestring    >=0.10.4.0 && <0.11-    , containers    >=0.5.5.1  && <0.7-    , text          >=1.2.3.0  && <1.3-    , transformers  >=0.3.0.0  && <0.6--  if !impl(ghc >=8.0)-    build-depends: semigroups >=0.18.5 && <0.19+    , base          >=4.7.0.2  && <4.23+    , bytestring    >=0.10.8.2 && <0.13+    , containers    >=0.6.0.1  && <0.9    -- Other dependencies   build-depends:-      attoparsec-    , base-compat        >=0.10.5   && <0.11-    , lattices           >=2        && <2.1+    , lattices           >=2        && <2.3     , MemoTrie           >=0.6.9    && <0.7-    , QuickCheck         >=2.12.6.1 && <2.13+    , QuickCheck         >=2.16.0.0 && <2.19     , range-set-list     >=0.1.3    && <0.2-    , regex-applicative  >=0.3.3    && <0.4-    , semigroupoids      >=5.3.2    && <5.4-    , step-function      >=0.2      && <0.3+    , regex-applicative  >=0.3.4    && <0.4+    , semigroupoids      >=5.3.2    && <6.1+    , step-function      >=0.2.1    && <0.3    other-extensions:     CPP@@ -70,8 +77,8 @@     Kleene     Kleene.Classes     Kleene.DFA-    Kleene.ERE     Kleene.Equiv+    Kleene.ERE     Kleene.Functor     Kleene.Functor.NonEmpty     Kleene.Monad@@ -79,14 +86,28 @@    -- "Internal-ish" modules   exposed-modules:+    Kleene.Internal.Functor     Kleene.Internal.Partition     Kleene.Internal.Pretty+    Kleene.Internal.RE     Kleene.Internal.Sets -  other-modules:-    Kleene.Internal.Functor-    Kleene.Internal.RE+  x-docspec-options:+    -XOverloadedStrings --check-properties "--property-variables=c p r s t q" -  ghc-options:      -Wall-  hs-source-dirs:   src+test-suite kleene-utf8   default-language: Haskell2010+  ghc-options:      -Wall+  hs-source-dirs:   tests+  type:             exitcode-stdio-1.0+  main-is:          kleene-utf8.hs+  build-depends:+    , base+    , bytestring+    , kleene++  -- test dependencies+  build-depends:+    , tasty             ^>=1.4.0.3  || ^>=1.5+    , tasty-hunit       ^>=0.10.0.3+    , tasty-quickcheck  ^>=0.11.1
src/Kleene.hs view
@@ -78,11 +78,11 @@ -- >>> import Kleene.RE (generate) -- -- >>> traverse_ print $ take 5 $ generate (curry QC.choose) 42 re--- "abcabcabcabcabcabcdefyz"--- "abcabcabcabcdefyz"--- "abcabcabcabcabcabcabcabcabcdefx"+-- "abcdefx" -- "abcabcdefx"--- "abcabcabcabcabcabcdefyz"+-- "abcdefyz"+-- "abcabcabcabcabcabcabcdefyz"+-- "abcabcabcabcabcabcabcdefyz" -- -- In addition to the "normal" regular expressions, there are /extended regular expressions/. -- Regular expressions which we can 'complement', and therefore intersect:@@ -164,6 +164,7 @@     FiniteKleene (..),     Derivate (..),     Match (..),+    Equivalent (..),     TransitionMap (..),     Complement (..),     ToLatin1 (..),
src/Kleene/Classes.hs view
@@ -3,9 +3,6 @@ {-# LANGUAGE GADTs                  #-} module Kleene.Classes where -import Prelude ()-import Prelude.Compat- import Data.Char                          (ord) import Data.Foldable                      (toList) import Data.Function.Step.Discrete.Closed (SF)
src/Kleene/DFA.hs view
@@ -1,9 +1,9 @@-{-# LANGUAGE BangPatterns           #-}-{-# LANGUAGE FlexibleInstances      #-}-{-# LANGUAGE FunctionalDependencies #-}-{-# LANGUAGE GADTs                  #-}-{-# LANGUAGE Safe                   #-}-{-# LANGUAGE ScopedTypeVariables    #-}+{-# LANGUAGE BangPatterns          #-}+{-# LANGUAGE FlexibleInstances     #-}+{-# LANGUAGE GADTs                 #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE Safe                  #-}+{-# LANGUAGE ScopedTypeVariables   #-} {-# OPTIONS_GHC -fno-warn-orphans #-} module Kleene.DFA (     DFA (..),@@ -19,9 +19,6 @@     toDot',     ) where -import Prelude ()-import Prelude.Compat- import Algebra.Lattice        (BoundedJoinSemiLattice (..), BoundedMeetSemiLattice (..), Lattice (..)) import Data.IntMap       (IntMap)@@ -44,6 +41,29 @@ import           Kleene.Internal.Pretty import qualified Kleene.Internal.RE     as RE +-- $setup+-- >>> :set -XOverloadedStrings+-- >>> import Data.Foldable (traverse_)+-- >>> import Data.Semigroup (Semigroup (..))+-- >>> import Algebra.Lattice ((/\))+-- >>> import Kleene.Classes+-- >>> import Kleene.Internal.Pretty (putPretty)+-- >>> import Test.QuickCheck ((===))+-- >>> import qualified Test.QuickCheck as QC+-- >>> import qualified Kleene.RE as RE+-- >>> import qualified Kleene.ERE as ERE+-- >>> import qualified Data.RangeSet.Map as RSet+--+-- >>> newtype Smaller a = Smaller a deriving (Show)+-- >>> let intLog2 = (`div` 10)+-- >>> instance QC.Arbitrary a => QC.Arbitrary (Smaller a) where arbitrary = QC.scale intLog2 QC.arbitrary; shrink (Smaller a) = map Smaller (QC.shrink a)+--+-- >>> let asREChar :: RE.RE Char -> RE.RE Char; asREChar = id++-------------------------------------------------------------------------------+-- DFA+-------------------------------------------------------------------------------+ -- | Deterministic finite automaton. -- -- A deterministic finite automaton (DFA) over an alphabet \(\Sigma\) (type@@ -234,7 +254,7 @@ -- -- For 'RE.string' regular expressions, @'toRE' . 'fromRE' = 'id'@: ----- prop> let s = take 5 s' in RE.string (s :: String) === toRE (fromRE (RE.string s))+-- prop> let s' = take 5 s in RE.string (s' :: String) === toRE (fromRE (RE.string s')) -- -- But in general it isn't: --@@ -541,17 +561,3 @@         , let acc = if IntSet.member i (dfaAcceptable dfa) then "+" else ""         , let bh = if IntSet.member i $ dfaBlackholes dfa then " -- black hole" else ""         ]---- $setup--- >>> :set -XOverloadedStrings--- >>> import Data.Foldable (traverse_)--- >>> import Algebra.Lattice ((/\))------ >>> import Test.QuickCheck ((===))--- >>> import qualified Test.QuickCheck as QC------ >>> newtype Smaller a = Smaller a deriving (Show)--- >>> let intLog2 = (`div` 10)--- >>> instance QC.Arbitrary a => QC.Arbitrary (Smaller a) where arbitrary = QC.scale intLog2 QC.arbitrary; shrink (Smaller a) = map Smaller (QC.shrink a)------ >>> let asREChar :: RE.RE Char -> RE.RE Char; asREChar = id
src/Kleene/ERE.hs view
@@ -1,9 +1,9 @@-{-# LANGUAGE BangPatterns           #-}-{-# LANGUAGE FlexibleInstances      #-}-{-# LANGUAGE FunctionalDependencies #-}-{-# LANGUAGE GADTs                  #-}-{-# LANGUAGE Safe                   #-}-{-# LANGUAGE ScopedTypeVariables    #-}+{-# LANGUAGE BangPatterns          #-}+{-# LANGUAGE FlexibleInstances     #-}+{-# LANGUAGE GADTs                 #-}+{-# LANGUAGE MultiParamTypeClasses #-}+{-# LANGUAGE Safe                  #-}+{-# LANGUAGE ScopedTypeVariables   #-} module Kleene.ERE (     ERE (..),     -- * Construction@@ -16,6 +16,7 @@     --     empty,     eps,+    everything,     char,     charRange,     anyChar,@@ -40,10 +41,6 @@     isEverything,     ) where -import Data.Semigroup (Semigroup (..))-import Prelude ()-import Prelude.Compat- import Algebra.Lattice        (BoundedJoinSemiLattice (..), BoundedMeetSemiLattice (..), Lattice (..)) import Control.Applicative (liftA2)@@ -65,6 +62,21 @@ import           Kleene.Internal.Pretty import qualified Kleene.Internal.RE        as RE +-- $setup+-- >>> import Algebra.Lattice ((/\), (\/), top, bottom)+-- >>> import Data.Semigroup (Semigroup (..))+-- >>> import Control.Monad (void)+-- >>> import Data.Foldable (traverse_)+-- >>> import Data.List (sort)+-- >>> import Test.QuickCheck ((===))+-- >>> import qualified Test.QuickCheck as QC+-- >>> import qualified Data.Map as Map+-- >>> import qualified Data.Function.Step.Discrete.Closed as SF+--+-- >>> import Kleene.Classes (match)+-- >>> import Kleene.Internal.Pretty (putPretty, pretty)+-- >>> let asEREChar :: ERE Char -> ERE Char; asEREChar = id+ -- | Extended regular expression -- -- It's both, /Kleene/ and /Boolean/ algebra. (If we add only intersections, it@@ -185,7 +197,7 @@     rs1 = concatMap f rs0      f (EREAppend rs) = rs-    f r             = [r]+    f r              = [r]  -- | Union of regular expressions. --@@ -614,19 +626,3 @@     toLatin1 (EREUnion rs xs) = C.fromRSet (C.toLatin1 rs) \/ unions (map C.toLatin1 (Set.toList  xs))     toLatin1 (EREStar r)      = star (C.toLatin1 r)     toLatin1 (ERENot r)       = complement (C.toLatin1 r)------------------------------------------------------------------------------------ Doctest------------------------------------------------------------------------------------ $setup--- >>> :set -XOverloadedStrings--- >>> import Control.Monad (void)--- >>> import Data.Foldable (traverse_)--- >>> import Data.List (sort)------ >>> import Test.QuickCheck ((===))--- >>> import qualified Test.QuickCheck as QC------ >>> import Kleene.Classes (match)--- >>> let asEREChar :: ERE Char -> ERE Char; asEREChar = id
src/Kleene/Equiv.hs view
@@ -7,16 +7,21 @@ {-# LANGUAGE UndecidableInstances       #-} module Kleene.Equiv where -import Prelude ()-import Prelude.Compat--import Algebra.Lattice    (BoundedJoinSemiLattice (..), BoundedMeetSemiLattice (..), Lattice (..), joinLeq)+import Algebra.Lattice+       (BoundedJoinSemiLattice (..), BoundedMeetSemiLattice (..), Lattice (..),+       joinLeq) import Algebra.PartialOrd (PartialOrd (..)) import Data.Semigroup     (Semigroup (..))  import Kleene.Classes import Kleene.Internal.Pretty +-- $setup+-- >>> import Kleene.RE (RE)+-- >>> import Kleene.Classes+-- >>> import Algebra.PartialOrd (leq)+-- >>> import Data.Semigroup (Semigroup (..))+ -- | Regular-expressions for which '==' is 'equivalent'. -- -- >>> let re1 = star "a" <> "a" :: RE Char@@ -56,6 +61,3 @@ deriving instance Match      c (r c) => Match      c (Equiv r c) deriving instance Equivalent c (r c) => Equivalent c (Equiv r c) deriving instance Complement c (r c) => Complement c (Equiv r c)---- $setup--- >>> import Kleene.RE (RE)
src/Kleene/Functor.hs view
@@ -1,4 +1,4 @@-{-# LANGUAGE Safe  #-}+{-# LANGUAGE Safe #-} module Kleene.Functor (     K,     Greediness (..),
src/Kleene/Functor/NonEmpty.hs view
@@ -6,6 +6,7 @@     Greediness (..),     -- * Constructors     some1,+    few1,     anyChar,     oneof,     char,@@ -25,9 +26,6 @@     nullableProof,     ) where -import Prelude ()-import Prelude.Compat- import Control.Applicative (Alternative (..), liftA2) import Data.Foldable       (toList) import Data.Functor.Alt    ((<!>))@@ -46,6 +44,18 @@ import           Kleene.Internal.Sets import qualified Kleene.RE               as RE +-- $setup+--+-- >>> import Control.Applicative (optional, Alternative (..))+-- >>> import Data.Functor.Apply (Apply (..))+-- >>> import Data.List.NonEmpty (NonEmpty (..))+-- >>> import Kleene.Functor (Greediness (..), K (..))+-- >>> import Data.Foldable (toList)+-- >>> import Kleene.Internal.Pretty (putPretty)+-- >>> import qualified Kleene.RE as RE+-- >>> import qualified Kleene.Classes as C+-- >>> import qualified Text.Regex.Applicative as R+ -- | 'Applicative' 'Functor' regular expression. data K1 c a where     K1Empty  :: K1 c a@@ -276,12 +286,3 @@ -- instance c ~ Char => Pretty (K1 c a) where     pretty = pretty . toRE------------------------------------------------------------------------------------ Doctest------------------------------------------------------------------------------------ $setup------ >>> :set -XOverloadedStrings--- >>> import Control.Applicative (optional)
src/Kleene/Internal/Functor.hs view
@@ -1,6 +1,7 @@ {-# LANGUAGE CPP   #-} {-# LANGUAGE GADTs #-} {-# LANGUAGE Safe  #-}+{-# OPTIONS_HADDOCK not-home #-} module Kleene.Internal.Functor (     K (..),     Greediness (..),@@ -25,24 +26,35 @@     toRA,     ) where -import Prelude ()-import Prelude.Compat- import Control.Applicative (Alternative (..), liftA2) import Data.Foldable       (toList) import Data.Functor.Apply  (Apply (..)) import Data.RangeSet.Map   (RSet) import Data.String         (IsString (..)) +import qualified Data.Functor.Alt       as Alt import qualified Data.RangeSet.Map      as RSet import qualified Text.Regex.Applicative as R-import qualified Data.Functor.Alt       as Alt  import qualified Kleene.Classes         as C import           Kleene.Internal.Pretty import           Kleene.Internal.Sets import qualified Kleene.RE              as RE ++-- $setup+--+-- >>> import Control.Applicative (Alternative (..), liftA2)+-- >>> import Data.Semigroup (Semigroup (..))+-- >>> import Kleene.Internal.Pretty (putPretty)+-- >>> import qualified Kleene.Classes as C+-- >>> import qualified Kleene.RE as RE+-- >>> import qualified Text.Regex.Applicative as R++-------------------------------------------------------------------------------+-- Functor RE+-------------------------------------------------------------------------------+ -- | Star behaviour data Greediness     = Greedy    -- ^ 'many'@@ -70,7 +82,7 @@     fmap f (KPure x)       = KPure (f x)     fmap f (KMap g k)      = KMap (f . g) k     fmap f (KAppend g a b) = KAppend (\x y -> f (g x y)) a b-    fmap f k                    = KMap f k+    fmap f k               = KMap f k  instance Apply (K c) where     KEmpty <.> _ = KEmpty@@ -272,11 +284,3 @@ -- instance c ~ Char => Pretty (K c a) where     pretty = pretty . toRE------------------------------------------------------------------------------------ Doctest------------------------------------------------------------------------------------ $setup------ >>> :set -XOverloadedStrings
src/Kleene/Internal/Partition.hs view
@@ -1,22 +1,29 @@ {-# LANGUAGE Safe #-}+{-# OPTIONS_HADDOCK not-home #-} module Kleene.Internal.Partition where -import Prelude ()-import Prelude.Compat-import Data.Semigroup (Semigroup (..))- import Data.Foldable      (toList) import Data.List.NonEmpty (NonEmpty (..)) import Data.RangeSet.Map  (RSet) import Data.Set           (Set)  import qualified Data.Function.Step.Discrete.Closed as SF-import qualified Data.List.NonEmpty          as NE+import qualified Data.List.NonEmpty                 as NE import qualified Data.RangeSet.Map                  as RSet import qualified Data.Set                           as Set  import Test.QuickCheck +-- $setup+-- >>> import Data.Word+-- >>> import Data.Semigroup (Semigroup (..))+-- >>> import Test.QuickCheck (Arbitrary (..), (===), (==>))+-- >>> import Data.RangeSet.Map (RSet)+-- >>> import qualified Data.RangeSet.Map as RSet+--+-- >>> let asPartitionChar :: Partition Char -> Partition Char; asPartitionChar = id+-- >>> instance (Ord a, Enum a, Arbitrary a) => Arbitrary (RSet a) where arbitrary = fmap RSet.fromRangeList arbitrary+ -- | 'Partition' devides type into disjoint connected partitions. -- -- /Note:/ we could have non-connecter partitions too,@@ -172,14 +179,3 @@     (f maxBound)   where     as = toList p------------------------------------------------------------------------------------ Doctest------------------------------------------------------------------------------------ $setup--- >>> import Data.Word--- >>> import Test.QuickCheck ((===))------ >>> let asPartitionChar :: Partition Char -> Partition Char; asPartitionChar = id--- >>> instance (Ord a, Enum a, Arbitrary a) => Arbitrary (RSet a) where arbitrary = fmap RSet.fromRangeList arbitrary
src/Kleene/Internal/Pretty.hs view
@@ -1,12 +1,10 @@ {-# LANGUAGE GADTs #-} {-# LANGUAGE Safe  #-}+{-# OPTIONS_HADDOCK not-home #-} module Kleene.Internal.Pretty (     Pretty (..),     putPretty,     ) where--import Prelude ()-import Prelude.Compat  import Data.Monoid          (Endo (..)) import Data.RangeSet.Map    (RSet)
src/Kleene/Internal/RE.hs view
@@ -4,6 +4,7 @@ {-# LANGUAGE GADTs                  #-} {-# LANGUAGE Safe                   #-} {-# LANGUAGE ScopedTypeVariables    #-}+{-# OPTIONS_HADDOCK not-home #-} module Kleene.Internal.RE (     RE (..),     -- * Construction@@ -15,6 +16,7 @@     --     empty,     eps,+    everything,     char,     charRange,     anyChar,@@ -37,10 +39,6 @@     nullableProof,     ) where -import Prelude ()-import Prelude.Compat-import Data.Semigroup (Semigroup (..))- import Control.Applicative (liftA2) import Data.Foldable       (toList) import Data.List           (foldl')@@ -61,6 +59,30 @@ import qualified Kleene.Internal.Partition as P import           Kleene.Internal.Pretty +-- $setup+-- >>> :set -XOverloadedStrings+-- >>> import Control.Monad (void)+-- >>> import Data.Foldable (traverse_)+-- >>> import Data.List (sort)+-- >>> import Data.Maybe (isJust)+-- >>> import Data.Semigroup (Semigroup (..))+--+-- >>> import Test.QuickCheck ((===))+-- >>> import qualified Test.QuickCheck as QC+-- >>> import qualified Data.Map as Map+-- >>> import qualified Data.Function.Step.Discrete.Closed as SF+--+-- >>> import Kleene.Classes (match)+-- >>> import Kleene.Internal.Pretty (putPretty, pretty)+-- >>> import Algebra.Lattice (bottom, (\/))+-- >>> import Kleene.RE ()+--+-- >>> let asREChar :: RE Char -> RE Char; asREChar = id++-------------------------------------------------------------------------------+-- RE+-------------------------------------------------------------------------------+ -- | Regular expression -- -- Constructors are exposed, but you should use@@ -165,10 +187,10 @@         [r] -> r         rs  -> REAppend rs   where-    -- flatten one level of REAppend     rs1 = concatMap f rs0 -    f (REAppend rs) = rs+    f :: RE c -> [RE c]+    f (REAppend rs) = concatMap f rs     f r             = [r]  -- | Union of regular expressions.@@ -368,7 +390,7 @@  nullableProof (REStar r)     | Just r' <- nullableProof r = Just (r' <> REStar r')-    | otherwise                  = Just (r <> REStar r) +    | otherwise                  = Just (r <> REStar r)  ------------------------------------------------------------------------------- -- isEmpty@@ -527,9 +549,9 @@ -- "abc" -- -- >>> example $ star $ "a" \/ "b"--- "aaaaba"--- "bbba"--- "abbbbaaaa"+-- ""+-- "bbaabbaaba"+-- "b" -- -- >>> example empty --@@ -654,23 +676,3 @@     toLatin1 (REAppend xs)   = appends (map C.toLatin1 xs)     toLatin1 (REUnion rs xs) = C.fromRSet (C.toLatin1 rs) \/ unions (map C.toLatin1 (Set.toList  xs))     toLatin1 (REStar r)      = star (C.toLatin1 r)------------------------------------------------------------------------------------ Doctest------------------------------------------------------------------------------------ $setup--- >>> :set -XOverloadedStrings--- >>> import Control.Monad (void)--- >>> import Data.Foldable (traverse_)--- >>> import Data.List (sort)--- >>> import Data.Maybe (isJust)------ >>> import Test.QuickCheck ((===))--- >>> import qualified Test.QuickCheck as QC------ >>> import Kleene.Classes (match)--- >>> import Algebra.Lattice (bottom)--- >>> import Kleene.RE ()------ >>> let asREChar :: RE Char -> RE Char; asREChar = id
src/Kleene/Internal/Sets.hs view
@@ -1,8 +1,9 @@ {-# LANGUAGE Safe #-}+{-# OPTIONS_HADDOCK not-home #-} -- | Character sets. module Kleene.Internal.Sets (     dotRSet,-    ) where+) where  import Data.RangeSet.Map (RSet) 
src/Kleene/Monad.hs view
@@ -37,10 +37,6 @@     isEps,     ) where -import Prelude ()-import Prelude.Compat-import Data.Semigroup (Semigroup (..))- import Control.Applicative (liftA2) import Control.Monad       (ap) import Data.Foldable       (toList)@@ -54,8 +50,21 @@ import qualified Kleene.Classes         as C import           Kleene.Internal.Pretty +-- $setup+-- >>> :set -XOverloadedStrings+-- >>> import Data.Foldable (traverse_)+-- >>> import Data.List (sort)+-- >>> import Kleene.Internal.Pretty (putPretty)+--+-- >>> import Test.QuickCheck ((===))+-- >>> import qualified Test.QuickCheck as QC+--+-- >>> import Kleene.RE (RE)+-- >>> import Kleene.Classes (match)+-- >>> let asMBool :: M Bool -> M Bool; asMBool = id+ -- | Regular expression which has no restrictions on the elements.--- Therefore we can have 'Monad' instance, i.e. have a regexp where +-- Therefore we can have 'Monad' instance, i.e. have a regexp where -- characters are regexps themselves. -- -- Because there are no optimisations, it's better to work over small alphabets.@@ -71,23 +80,20 @@ -- ^..*.$ -- data M c-    = MChars [c]        -- ^ One of the characters-    | MAppend [M c]     -- ^ Concatenation+    = MAppend [M c]     -- ^ Concatenation     | MUnion [c] [M c]  -- ^ Union     | MStar (M c)       -- ^ Kleene star   deriving (Eq, Ord, Show, Functor, Foldable, Traversable)  instance Applicative M where-    pure = MChars . pure+    pure = char     (<*>) = ap  instance Monad M where     return = pure -    MChars []    >>= _  = MChars []-    MChars cs    >>= k  = appends (map k cs)     MAppend rs   >>= k  = appends (map (>>= k) rs)-    MUnion cs rs >>= k  = unions (map (>>= k) (MChars cs : rs))+    MUnion cs rs >>= k  = unions (appends (map k cs) : map (>>= k) rs)     MStar r      >>= k  = star (r >>= k)  -------------------------------------------------------------------------------@@ -102,7 +108,7 @@ -- prop> match (empty :: M Char) (s :: String) === False -- empty :: M c-empty = MChars []+empty = MUnion [] []  -- | Empty string. /Note:/ different than 'empty'. --@@ -123,7 +129,7 @@ -- ^x$ -- char :: c -> M c-char = MChars . pure+char c = MUnion [c] []  -- | /Note:/ we know little about @c@. --@@ -131,7 +137,7 @@ -- ^[abcdefghijklmnopqrstuvwxyz]$ -- charRange :: Enum c => c -> c -> M c-charRange c c' = MChars [c .. c']+charRange c c' = MUnion [c .. c'] []   -- | Any character. /Note:/ different than dot!@@ -140,7 +146,7 @@ -- ^[01]$ -- anyChar :: (Bounded c, Enum c) => M c-anyChar = MChars [minBound .. maxBound]+anyChar = MUnion [minBound .. maxBound] []  -- | Concatenate regular expressions. --@@ -163,27 +169,19 @@ -- unions :: [M c] -> M c unions = uncurry mk . foldMap f where-    mk cs rss-        | null rss = MChars cs-        | null cs = case rss of-            []  -> empty-            [r] -> r-            _   -> MUnion cs rss-        | otherwise    = MUnion cs rss-     f (MUnion cs rs) = (cs, rs)-    f (MChars cs)    = (cs, [])     f r              = ([], [r]) +    mk [] [r] = r+    mk cs rs = MUnion cs rs+ -- | Kleene star. -- star :: M c -> M c star r = case r of     MStar _                    -> r     MAppend []                 -> eps-    MChars cs | null cs        -> eps     MUnion cs rs | any isEps rs -> case rs' of-        []             -> star (MChars cs)         [r'] | null cs -> star r'         _              -> MStar (MUnion cs rs')       where@@ -203,8 +201,8 @@ -- string :: [c] -> M c string []  = eps-string [c] = MChars [c]-string cs  = MAppend $ map (MChars . pure) cs+string [c] = char c+string cs  = MAppend $ map char cs  instance C.Kleene  (M c) where     empty      = empty@@ -233,7 +231,6 @@ -- False -- nullable :: M c -> Bool-nullable (MChars _)      = False nullable (MAppend rs)    = all nullable rs nullable (MUnion _cs rs) = any nullable rs nullable (MStar _)       = True@@ -252,7 +249,6 @@ -- ^yz(xyz)*$ -- derivate :: (Eq c, Enum c, Bounded c) => c -> M c -> M c-derivate c (MChars cs)     = derivateChars c cs derivate c (MUnion cs rs)  = unions $ derivateChars c cs : [ derivate c r | r <- toList rs] derivate c (MAppend rs)    = derivateAppend c rs derivate c rs@(MStar r)    = derivate c r <> rs@@ -285,8 +281,8 @@  -- | Whether 'M' is (structurally) equal to 'empty'. isEmpty :: M c -> Bool-isEmpty (MChars rs) = null rs-isEmpty _           = False+isEmpty (MUnion cs rs) = null cs && null rs+isEmpty _              = False  -- | Whether 'M' is (structurally) equal to 'eps'. isEps :: M c -> Bool@@ -306,9 +302,9 @@ -- "abc" -- -- >>> example $ star $ unions ["a", "b"]--- "ababbb"--- "baab"--- "abbababaa"+-- ""+-- "aaababaaab"+-- "a" -- -- xx >>> example empty --@@ -324,7 +320,6 @@  generator :: M c -> QC.Gen [c] generator = go where-    go (MChars cs)    = goChars cs     go (MAppend rs)   = concat <$> traverse go rs     go (MUnion cs rs)         | null cs   = QC.oneof [ go r | r <- toList rs ]@@ -349,7 +344,6 @@ -- ^[a-z]$ -- toKleene :: C.CharKleene c k => M c -> k-toKleene (MChars cs)    = C.oneof cs toKleene (MAppend rs)   = C.appends (map toKleene rs) toKleene (MUnion cs rs) = C.unions (C.oneof cs : map toKleene rs) toKleene (MStar r)      = C.star (toKleene r)@@ -372,7 +366,7 @@ instance (Eq c, Enum c, Bounded c, QC.Arbitrary c) => QC.Arbitrary (M c) where     arbitrary = QC.sized arb where         c :: QC.Gen (M c)-        c = MChars <$> QC.arbitrary+        c = char <$> QC.arbitrary          arb :: Int -> QC.Gen (M c)         arb n | n <= 0    = QC.oneof [c, fmap char QC.arbitrary, pure eps]@@ -388,7 +382,6 @@             n2 = n `div` 2  instance (QC.CoArbitrary c) => QC.CoArbitrary (M c) where-    coarbitrary (MChars cs)    = QC.variant (0 :: Int) . QC.coarbitrary cs     coarbitrary (MAppend rs)   = QC.variant (1 :: Int) . QC.coarbitrary rs     coarbitrary (MUnion cs rs) = QC.variant (2 :: Int) . QC.coarbitrary (cs, rs)     coarbitrary (MStar r)      = QC.variant (3 :: Int) . QC.coarbitrary r@@ -407,11 +400,9 @@         go p (MAppend rs)             = parens p $ goMany id rs         go p (MUnion cs rs)-            | null cs   = goUnion p rs             | null rs   = prettySList cs-            | otherwise = goUnion p (MChars cs : rs)-        go _ (MChars cs)-            = prettySList cs+            | null cs   = goUnion p rs+            | otherwise = goUnion p (MUnion cs [] : rs)          goUnion p rs             | elem eps rs = parens p $ goUnion' True . showChar '?'@@ -435,19 +426,3 @@         prettySList :: [c] -> ShowS         prettySList [c] = prettyS c         prettySList xs  = showChar '[' . foldr (\a b -> prettyS a . b) (showChar ']') xs------------------------------------------------------------------------------------ Doctest------------------------------------------------------------------------------------ $setup--- >>> :set -XOverloadedStrings--- >>> import Data.Foldable (traverse_)--- >>> import Data.List (sort)------ >>> import Test.QuickCheck ((===))--- >>> import qualified Test.QuickCheck as QC------ >>> import Kleene.RE (RE)--- >>> import Kleene.Classes (match)--- >>> let asMBool :: M Bool -> M Bool; asMBool = id
src/Kleene/RE.hs view
@@ -9,6 +9,7 @@     --     empty,     eps,+    everything,     char,     charRange,     anyChar,@@ -32,5 +33,5 @@     ) where  -- This to include orphans.-import Kleene.Internal.RE import Kleene.DFA ()+import Kleene.Internal.RE
+ tests/kleene-utf8.hs view
@@ -0,0 +1,135 @@+{-# LANGUAGE CPP #-}+module Main (main) where++import Data.Bits        (shiftR, (.&.), (.|.))+import Data.Char        (ord)+import Data.Semigroup   ((<>))+import Data.Word        (Word8)+import Test.Tasty       (defaultMain, testGroup)+import Test.Tasty.HUnit (assertBool, testCase)++import Kleene+import Kleene.DFA (fromRE, toRE)++#if MIN_VERSION_bytestring(0,11,2)+import Test.Tasty.QuickCheck (label, testProperty, (===))++import qualified Data.ByteString as BS+#endif++main :: IO ()+main = do+    -- print utf8char2+    -- print utf8char3+    -- print utf8char4+    defaultMain $ testGroup "kleene-utf8"+        [ testCase "brute ≃ brute'" $ do+            assertBool "not equiv" (equivalent utf8char1 utf8char2)+        , testCase "brute' ≃ manual1" $ do+            assertBool "not equiv" (equivalent utf8char2 utf8char3)+        , testCase "manual1 ≃ manual2" $ do+            assertBool "not equiv" (equivalent utf8char3 utf8char4)+        , testCase "brute ≃ manual2" $ do+            assertBool "not equiv" (equivalent utf8char1 utf8char4)++#if MIN_VERSION_bytestring(0,11,2)+        , testProperty "isValidUtf8" $ \w8s ->+            let bs = BS.pack w8s+                isValid = BS.isValidUtf8 bs+            in label (show isValid) $ isValid === match (star utf8char4) w8s+#endif+        ]++-------------------------------------------------------------------------------+-- Bruteforce definition+-------------------------------------------------------------------------------++utf8char1 :: RE Word8+utf8char1 = unions+    [ string (encodeStringUtf8 [c])+    | c <- [ '\0' .. maxBound ]+    ]++-------------------------------------------------------------------------------+-- Derived definition+-------------------------------------------------------------------------------++utf8charDFA1 :: DFA Word8+utf8charDFA1 = fromRE utf8char1++utf8char2 :: RE Word8+utf8char2 = toRE utf8charDFA1++-------------------------------------------------------------------------------+-- Written out definition+-------------------------------------------------------------------------------++utf8char3 :: RE Word8+utf8char3 = unions+    [ charRange 0x00 0x7F+    , sub1 <> charRange 0x80 0xBF+    ]+  where+    sub1 = unions+        [ charRange 0xC2 0xDF+        , charRange 0xE0 0xE0 <> charRange 0xa0 0xBF+        , charRange 0xED 0xED <> charRange 0x80 0x9F+        , sub2 <> charRange 0x80 0xBF+        ]++    sub2 = unions+        [ charRange 0xE1 0xEC+        , charRange 0xEE 0xEF+        , charRange 0xF0 0xF0 <> charRange 0x90 0xBF+        , charRange 0xF1 0xF3 <> charRange 0x80 0xBF+        , charRange 0xF4 0xF4 <> charRange 0x80 0x8f+        ]++-------------------------------------------------------------------------------+-- Manual definition, how human would written it+-------------------------------------------------------------------------------++utf8char4 :: RE Word8+utf8char4 = unions+    [ charRange 0x00 0x7F+    , charRange 0xC2 0xDF <> charRange 0x80 0xBF+    , charRange 0xE0 0xE0 <> charRange 0xa0 0xBF <> charRange 0x80 0xBF+    , charRange 0xE1 0xEC <> charRange 0x80 0xBF <> charRange 0x80 0xBF+    , charRange 0xED 0xED <> charRange 0x80 0x9F <> charRange 0x80 0xBF+    , charRange 0xEE 0xEF <> charRange 0x80 0xBF <> charRange 0x80 0xBF+    , charRange 0xF0 0xF0 <> charRange 0x90 0xBF <> charRange 0x80 0xBF <> charRange 0x80 0xBF+    , charRange 0xF1 0xF3 <> charRange 0x80 0xBF <> charRange 0x80 0xBF <> charRange 0x80 0xBF+    , charRange 0xF4 0xF4 <> charRange 0x80 0x8f <> charRange 0x80 0xBF <> charRange 0x80 0xBF+    ]++-------------------------------------------------------------------------------+-- UTF8 encoding+-------------------------------------------------------------------------------++encodeStringUtf8 :: String -> [Word8]+encodeStringUtf8 []        = []+encodeStringUtf8 (c:cs)+  | c <= '\x07F' = w8+                 : encodeStringUtf8 cs+  | c <= '\x7FF' = (0xC0 .|.  w8ShiftR  6          )+                 : (0x80 .|. (w8          .&. 0x3F))+                 : encodeStringUtf8 cs+  | c <= '\xD7FF'= (0xE0 .|.  w8ShiftR 12          )+                 : (0x80 .|. (w8ShiftR  6 .&. 0x3F))+                 : (0x80 .|. (w8          .&. 0x3F))+                 : encodeStringUtf8 cs+  | c <= '\xDFFF'= 0xEF : 0xBF : 0xBD -- U+FFFD+                 : encodeStringUtf8 cs+  | c <= '\xFFFF'= (0xE0 .|.  w8ShiftR 12          )+                 : (0x80 .|. (w8ShiftR  6 .&. 0x3F))+                 : (0x80 .|. (w8          .&. 0x3F))+                 : encodeStringUtf8 cs+  | otherwise    = (0xf0 .|.  w8ShiftR 18          )+                 : (0x80 .|. (w8ShiftR 12 .&. 0x3F))+                 : (0x80 .|. (w8ShiftR  6 .&. 0x3F))+                 : (0x80 .|. (w8          .&. 0x3F))+                 : encodeStringUtf8 cs+  where+    w8 = fromIntegral (ord c) :: Word8+    w8ShiftR :: Int -> Word8+    w8ShiftR = fromIntegral . shiftR (ord c)