packages feed

predicate-typed 0.7.0.0 → 0.7.1.0

raw patch · 14 files changed

+593/−244 lines, 14 filesdep ~thesePVP: major bump suggested

API removals or changes: PVP suggests a major version bump

Dependency ranges changed: these

API changes (from Hackage documentation)

- Predicate.Core: prtTree' :: Show x => POpts -> TT x -> String
- Predicate.Prelude: instance forall k (r :: Predicate.Util.ReplaceFnSub) (p :: k) x. (Predicate.Util.ReplaceFnSubC r, Predicate.Core.PP p x Data.Type.Equality.~ GHC.Base.String, Predicate.Core.P p x) => Predicate.Core.P (Predicate.Prelude.ReplaceFn r p) x
- Predicate.Util: PE :: !BoolP -> !String -> PE
- Predicate.Util: boolT2P :: Lens' (BoolT a) BoolP
- Predicate.Util: class ReplaceFnSubC (k :: ReplaceFnSub)
- Predicate.Util: colorBoolP :: POpts -> BoolP -> String
- Predicate.Util: data BoolP
- Predicate.Util: instance (GHC.Show.Show (Predicate.Util.HKD f GHC.Types.Int), GHC.Show.Show (Predicate.Util.HKD f Predicate.Util.Debug), GHC.Show.Show (Predicate.Util.HKD f Predicate.Util.Disp), GHC.Show.Show (Predicate.Util.HKD f (GHC.Base.String, Predicate.Util.PColor)), GHC.Show.Show (Predicate.Util.HKD f GHC.Types.Bool), GHC.Show.Show (Predicate.Util.HKD f (System.Console.Pretty.Color, System.Console.Pretty.Color))) => GHC.Show.Show (Predicate.Util.HOpts f)
- Predicate.Util: instance (Predicate.Util.GetColor c1, Predicate.Util.GetColor c2) => Predicate.Util.OptTC ('Predicate.Util.OOther c1 c2)
- Predicate.Util: instance Predicate.Util.ReplaceFnSubC 'Predicate.Util.RAppend
- Predicate.Util: instance Predicate.Util.ReplaceFnSubC 'Predicate.Util.ROverWrite
- Predicate.Util: instance Predicate.Util.ReplaceFnSubC 'Predicate.Util.RPrepend
- Predicate.Util: markBoundary :: POpts -> String -> String
- Predicate.Util: pBool :: Lens' PE BoolP
- Predicate.Util: prtTT :: POpts -> Identity (TT a) -> IO ()
- Predicate.Util: prtTTIO :: POpts -> IO (TT a) -> IO ()
- Predicate.Util: prtTree :: POpts -> Tree PE -> IO ()
+ Predicate.Core: prtTree :: Show x => POpts -> TT x -> String
+ Predicate.Prelude: data EnumFromThenTo p q r
+ Predicate.Prelude: data ToWeekDate p
+ Predicate.Prelude: data ToWeekYear p
+ Predicate.Prelude: instance forall k (p :: k) x. (Predicate.Core.P p x, Predicate.Core.PP p x Data.Type.Equality.~ Data.Time.Calendar.Days.Day) => Predicate.Core.P (Predicate.Prelude.ToWeekDate p) x
+ Predicate.Prelude: instance forall k (p :: k) x. (Predicate.Core.P p x, Predicate.Core.PP p x Data.Type.Equality.~ Data.Time.Calendar.Days.Day) => Predicate.Core.P (Predicate.Prelude.ToWeekYear p) x
+ Predicate.Prelude: instance forall k (r :: Predicate.Util.ReplaceFnSub) (p :: k) x. (Predicate.Util.GetReplaceFnSub r, Predicate.Core.PP p x Data.Type.Equality.~ GHC.Base.String, Predicate.Core.P p x) => Predicate.Core.P (Predicate.Prelude.ReplaceFn r p) x
+ Predicate.Prelude: instance forall k1 k2 (p :: k2) a (q :: k1). (Predicate.Core.P p a, Predicate.Core.P q a, Predicate.Core.PP p a Data.Type.Equality.~ GHC.Types.Bool, Predicate.Core.PP q a Data.Type.Equality.~ GHC.Types.Bool) => Predicate.Core.P (p Predicate.Prelude.&&~ q) a
+ Predicate.Prelude: instance forall k1 k2 (p :: k2) a (q :: k1). (Predicate.Core.P p a, Predicate.Core.P q a, Predicate.Core.PP p a Data.Type.Equality.~ GHC.Types.Bool, Predicate.Core.PP q a Data.Type.Equality.~ GHC.Types.Bool) => Predicate.Core.P (p Predicate.Prelude.||~ q) a
+ Predicate.Prelude: instance forall k1 k2 k3 (p :: k3) x (q :: k2) (r :: k1) a. (Predicate.Core.P p x, Predicate.Core.P q x, Predicate.Core.P r x, Predicate.Core.PP p x Data.Type.Equality.~ a, GHC.Show.Show a, Predicate.Core.PP q x Data.Type.Equality.~ a, Predicate.Core.PP r x Data.Type.Equality.~ a, GHC.Enum.Enum a) => Predicate.Core.P (Predicate.Prelude.EnumFromThenTo p q r) x
+ Predicate.Refined2: genRefined2 :: forall opts ip op i. (Refined2C opts ip op i, Show (PP ip i)) => Gen i -> Gen (Refined2 opts ip op i)
+ Predicate.Refined2: genRefined2P :: forall opts ip op i. (Refined2C opts ip op i, Show (PP ip i)) => Proxy '(opts, ip, op, i) -> Gen i -> Gen (Refined2 opts ip op i)
+ Predicate.Refined2: instance forall k1 k2 i (opts :: Predicate.Util.OptT) (ip :: k2) (op :: k1). (Test.QuickCheck.Arbitrary.Arbitrary i, Predicate.Refined2.Refined2C opts ip op i, GHC.Show.Show (Predicate.Core.PP ip i)) => Test.QuickCheck.Arbitrary.Arbitrary (Predicate.Refined2.Refined2 opts ip op i)
+ Predicate.Util: class GetReplaceFnSub (k :: ReplaceFnSub)
+ Predicate.Util: instance (GHC.Show.Show (Predicate.Util.HKD f GHC.Types.Int), GHC.Show.Show (Predicate.Util.HKD f Predicate.Util.Debug), GHC.Show.Show (Predicate.Util.HKD f Predicate.Util.Disp), GHC.Show.Show (Predicate.Util.HKD f (GHC.Base.String, Predicate.Util.PColor)), GHC.Show.Show (Predicate.Util.HKD f GHC.Types.Bool), GHC.Show.Show (Predicate.Util.HKD f (GHC.Types.Bool, Predicate.Util.SColor, Predicate.Util.SColor))) => GHC.Show.Show (Predicate.Util.HOpts f)
+ Predicate.Util: instance (Predicate.Util.GetBool b, Predicate.Util.GetColor c1, Predicate.Util.GetColor c2) => Predicate.Util.OptTC ('Predicate.Util.OOther b c1 c2)
+ Predicate.Util: instance GHC.Show.Show Predicate.Util.SColor
+ Predicate.Util: instance Predicate.Util.GetReplaceFnSub 'Predicate.Util.RAppend
+ Predicate.Util: instance Predicate.Util.GetReplaceFnSub 'Predicate.Util.ROverWrite
+ Predicate.Util: instance Predicate.Util.GetReplaceFnSub 'Predicate.Util.RPrepend
+ Predicate.Util: isPrime :: Int -> Bool
+ Predicate.Util: pureTryTest :: a -> IO (Either () a)
+ Predicate.Util: pureTryTestPred :: (String -> Bool) -> a -> IO (Either String (Either () a))
+ Predicate.Util: setOtherEffects :: POpts -> String -> String
+ Predicate.Util: type Other1 = 'OOther 'True 'Yellow 'Default
+ Predicate.Util: type Other2 = 'OOther 'True 'Default 'Default
- Predicate.Refined: prtRefinedIO :: forall opts p a. RefinedC opts p a => a -> IO (Either BoolP (Refined opts p a))
+ Predicate.Refined: prtRefinedIO :: forall opts p a. RefinedC opts p a => a -> IO (Either (BoolT Bool) (Refined opts p a))
- Predicate.Util: HOpts :: !HKD f Int -> !HKD f Debug -> !HKD f Disp -> !HKD f (String, PColor) -> ![String] -> !HKD f Int -> !HKD f (Color, Color) -> !HKD f Bool -> HOpts f
+ Predicate.Util: HOpts :: !HKD f Int -> !HKD f Debug -> !HKD f Disp -> !HKD f (String, PColor) -> ![String] -> !HKD f Int -> !HKD f (Bool, SColor, SColor) -> !HKD f Bool -> HOpts f
- Predicate.Util: OOther :: !Color -> !Color -> OptT
+ Predicate.Util: OOther :: !Bool -> !Color -> !Color -> OptT
- Predicate.Util: [oOther] :: HOpts f -> !HKD f (Color, Color)
+ Predicate.Util: [oOther] :: HOpts f -> !HKD f (Bool, SColor, SColor)
- Predicate.Util: getReplaceFnSub :: ReplaceFnSubC k => ReplaceFnSub
+ Predicate.Util: getReplaceFnSub :: GetReplaceFnSub k => ReplaceFnSub

Files

predicate-typed.cabal view
@@ -4,10 +4,10 @@ -- -- see: https://github.com/sol/hpack ----- hash: 50c224873b64d409685fdae3dead9b051e87bbe0a62f23783507eda242b4884d+-- hash: ce8bf201dfcc67f4335c139afa9cb860348bc6b07daa4e34ac23aff8db72dad2  name:           predicate-typed-version:        0.7.0.0+version:        0.7.1.0 synopsis:       Predicates, Refinement types and Dsl description:    Please see the README on GitHub at <https://github.com/gbwey/predicate-typed#readme> category:       Data@@ -66,7 +66,7 @@     , template-haskell     , text     , th-lift-    , these+    , these >=0.8     , time     , tree-view >=0.5   if impl(ghc >= 8.8)@@ -119,7 +119,7 @@     , template-haskell     , text     , th-lift-    , these+    , these >=0.8     , time     , tree-view >=0.5   if impl(ghc >= 8.8)@@ -166,7 +166,7 @@     , template-haskell     , text     , th-lift-    , these+    , these >=0.8     , time     , tree-view >=0.5   if impl(ghc >= 8.8)
src/Predicate/Core.hs view
@@ -45,7 +45,7 @@   , runPQBool
   , evalBool
   , evalQuick
-  , prtTree'
+  , prtTree
   ) where
 import Predicate.Util
 import GHC.TypeLits (Symbol,Nat,KnownSymbol,KnownNat)
@@ -72,7 +72,6 @@ evalQuick :: forall p i . P p i => i -> Either String (PP p i)
 evalQuick i = getValLRFromTT (runIdentity (eval (Proxy @p) (getOptT @'OL) i))
 
-
 -- | identity function
 --
 -- >>> pz @I 23
@@ -510,7 +509,7 @@       Nothing -> pure $ mkNode opts (FailT (msg0 <> " found Nothing")) (msg0 <> " found Nothing") []
 
 -- | expects Nothing otherwise it fails
--- if the value is Nothing then it returns \'Proxy a\' as this provides more information than '()'
+-- if the value is Nothing then it returns \'Proxy a\' as this provides type information
 --
 -- >>> pz @'Nothing Nothing
 -- PresentT Proxy
@@ -677,6 +676,30 @@     let b = Proxy @a
     in pure $ mkNode opts (PresentT b) ("'Proxy" <> show1 opts " | " a) []
 
+-- | typelevel 'BoolT'
+--
+-- >>> pz @'TrueT ()
+-- TrueT
+--
+-- >>> pz @'FalseT ()
+-- FalseT
+--
+-- >>> pz @('PresentT 123) ()
+-- PresentT False
+--
+-- >>> pz @('FailT '[]) ()
+-- FailT "'FailT _"
+--
+instance GetBoolT x b => P (b :: BoolT x) a where
+  type PP b a = Bool
+  eval _ opts _ = do
+    let msg0 = "'BoolT"
+    let ret = getBoolT @x @b
+    pure $ case ret of
+      Left b -> mkNodeB opts b (if b then "TrueT" else "FalseT") []
+      Right True -> mkNode opts (PresentT False) (msg0 <> " PresentT") []
+      Right False -> mkNode opts (FailT "'FailT _") (msg0 <> " FailT") []
+
 pan, pa, pu, pl, pz, pab, pub :: forall p a . (Show (PP p a), P p a) => a -> IO (BoolT (PP p a))
 -- | skips the evaluation tree and just displays the end result
 pz = run @'OZ @p
@@ -694,9 +717,13 @@ -- @
 pu = run @'OU @p
 -- | displays the evaluation tree using unicode and colors with background colors
--- | displays the evaluation tree using background colors
 pub = run @'OUB @p
 
+-- | evaluate a typelevel expression (use type applications to pass in the options and the expression)
+--
+-- >>> run @'OZ @Id 123
+-- PresentT 123
+--
 run :: forall opts p a
         . ( OptTC opts
           , Show (PP p a)
@@ -707,17 +734,17 @@   let opts = getOptT @opts
   pp <- eval (Proxy @p) opts a
   let r = pp ^. tBool
-  putStr $ prtTree' opts pp
+  putStr $ prtTree opts pp
   return r
 
-prtTree' :: Show x => POpts -> TT x -> String
-prtTree' opts pp =
+prtTree :: Show x => POpts -> TT x -> String
+prtTree opts pp =
   let r = pp ^. tBool
   in case oDebug opts of
        DZero -> ""
        DLite ->
              formatOMsg opts " >>> "
-          <> colorBoolT' opts r
+          <> colorBoolT opts r
           <> " "
           <> topMessage pp
           <> "\n"
@@ -759,27 +786,3 @@          pure $ case getValueLR opts msg0 qq (hhs <> [hh pp]) of
            Left e -> Left e
            Right q -> Right (p, q, pp, qq)
-
--- | typelevel 'BoolT'
---
--- >>> pz @'TrueT ()
--- TrueT
---
--- >>> pz @'FalseT ()
--- FalseT
---
--- >>> pz @('PresentT 123) ()
--- PresentT False
---
--- >>> pz @('FailT '[]) ()
--- FailT "'FailT _"
---
-instance GetBoolT x b => P (b :: BoolT x) a where
-  type PP b a = Bool
-  eval _ opts _ = do
-    let msg0 = "'BoolT"
-    let ret = getBoolT @x @b
-    pure $ case ret of
-      Left b -> mkNodeB opts b (if b then "TrueT" else "FalseT") []
-      Right True -> mkNode opts (PresentT False) (msg0 <> " PresentT") []
-      Right False -> mkNode opts (FailT "'FailT _") (msg0 <> " FailT") []
src/Predicate/Examples/Refined1.hs view
@@ -5,7 +5,6 @@ {-# OPTIONS -Wredundant-constraints #-}
 {-# OPTIONS -Wincomplete-record-updates #-}
 {-# OPTIONS -Wno-unused-imports #-}
-{-# LANGUAGE TypeOperators #-}
 {-# LANGUAGE UndecidableInstances #-}
 {-# LANGUAGE FlexibleContexts #-}
 {-# LANGUAGE AllowAmbiguousTypes #-}
src/Predicate/Examples/Refined2.hs view
@@ -278,9 +278,7 @@ -- >>> newRefined2 @'OZ @(ReadP Rational Id) @(Id > (11 % 1)) "13 % 3"
 -- Left "Step 2. False Boolean Check(op) | FalseP"
 --
--- >>> let tmString = "2018-10-19 14:53:11.5121359 UTC"
--- >>> let tm = read tmString :: UTCTime
--- >>> newRefined2 @'OZ @(ReadP UTCTime Id) @'True tmString
+-- >>> newRefined2 @'OZ @(ReadP UTCTime Id) @'True "2018-10-19 14:53:11.5121359 UTC"
 -- Right (Refined2 {r2In = 2018-10-19 14:53:11.5121359 UTC, r2Out = "2018-10-19 14:53:11.5121359 UTC"})
 --
 -- >>> :m + Data.Aeson
src/Predicate/Examples/Refined3.hs view
@@ -393,9 +393,7 @@ -- >>> newRefined3P (Proxy @(ReadShow' 'OZ Rational (Id > (11 % 1)))) "13 % 3"
 -- Left "Step 2. False Boolean Check(op) | FalseP"
 --
--- >>> let tmString = "2018-10-19 14:53:11.5121359 UTC"
--- >>> let tm = read tmString :: UTCTime
--- >>> newRefined3P (readshow @'OZ @UTCTime) tmString
+-- >>> newRefined3P (readshow @'OZ @UTCTime) "2018-10-19 14:53:11.5121359 UTC"
 -- Right (Refined3 {r3In = 2018-10-19 14:53:11.5121359 UTC, r3Out = "2018-10-19 14:53:11.5121359 UTC"})
 --
 -- >>> :m + Data.Aeson
src/Predicate/Prelude.hs view
@@ -31,7 +31,9 @@ module Predicate.Prelude (
   -- ** boolean expressions
     type (&&)
+  , type (&&~)
   , type (||)
+  , type (||~)
   , type (~>)
   , Not
   , Ands
@@ -127,6 +129,8 @@   , UnMkDay
   , MkDayExtra
   , MkDayExtra'
+  , ToWeekDate
+  , ToWeekYear
   , ToDay
   , ToTime
   , MkTime
@@ -241,6 +245,7 @@   , ToEnum
   , ToEnum'
   , EnumFromTo
+  , EnumFromThenTo
   -- *** bounded enum expressions
   , SuccB
   , SuccB'
@@ -1295,7 +1300,7 @@ --
 data ReplaceFn (o :: ReplaceFnSub) p
 
-instance (ReplaceFnSubC r
+instance (GetReplaceFnSub r
         , PP p x ~ String
         , P p x) => P (ReplaceFn r p) x where
   type PP (ReplaceFn r p) x = RReplace
@@ -2045,6 +2050,56 @@   type PP (MkDayExtra p) x = PP (MkDayExtraT p) x
   eval _ = eval (Proxy @(MkDayExtraT p))
 
+-- | get day of week
+--
+-- >>> pz @(Just (MkDay '(2020,7,11)) >> '(UnMkDay Id, ToWeekYear Id,ToWeekDate Id)) ()
+-- PresentT ((2020,7,11),28,(6,"Saturday"))
+--
+data ToWeekDate p
+
+instance ( P p x
+         , PP p x ~ Day
+         ) => P (ToWeekDate p) x where
+  type PP (ToWeekDate p) x = (Int, String)
+  eval _ opts x = do
+    let msg0 = "ToWeekDate"
+    pp <- eval (Proxy @p) opts x
+    pure $ case getValueLR opts msg0 pp [] of
+      Left e -> e
+      Right p ->
+        let (_, _week, dow) = toWeekDate p
+            dowString =
+              case dow of
+                 1 -> "Monday"
+                 2 -> "Tuesday"
+                 3 -> "Wednesday"
+                 4 -> "Thursday"
+                 5 -> "Friday"
+                 6 -> "Saturday"
+                 7 -> "Sunday"
+                 _ -> error $ "oops: ToWeekDate invalid " ++ show dow
+        in mkNode opts (PresentT (dow,dowString)) (show01 opts msg0 dow p) [hh pp]
+
+-- | get week number of the year
+--
+-- >>> pz @(Just (MkDay '(2020,7,11)) >> ToWeekYear Id) ()
+-- PresentT 28
+--
+data ToWeekYear p
+
+instance ( P p x
+         , PP p x ~ Day
+         ) => P (ToWeekYear p) x where
+  type PP (ToWeekYear p) x = Int
+  eval _ opts x = do
+    let msg0 = "ToWeekYear"
+    pp <- eval (Proxy @p) opts x
+    pure $ case getValueLR opts msg0 pp [] of
+      Left e -> e
+      Right p ->
+        let (_, week, _dow) = toWeekDate p
+        in mkNode opts (PresentT week) (show01 opts msg0 week p) [hh pp]
+
 class ToDayC a where
   getDay :: a -> Day
 instance ToDayC UTCTime where
@@ -2117,7 +2172,7 @@         in mkNode opts (PresentT ret) (show01 opts msg0 ret p) [hh pp]
 
 
--- | create a 'Time' from three int values passed in as year month and day
+-- | create a 'TimeOfDay' from three int values passed in as year month and day
 --
 -- >>> pz @(MkTime '(1,2,3 % 12345)) ()
 -- PresentT 01:02:00.000243013365
@@ -2168,6 +2223,12 @@ -- >>> pz @(ReadP UTCTime "2019-01-01 12:13:14.1234Z" >> ToTime Id >> UnMkTime Id) ()
 -- PresentT (12,13,70617 % 5000)
 --
+-- >>> pz @(ReadP UTCTime Id >> ToTime Id >> UnMkTime Id) "2020-07-22 08:01:14.127Z"
+-- PresentT (8,1,14127 % 1000)
+--
+-- >>> pz @(ReadP ZonedTime Id >> '(UnMkDay (ToDay Id), UnMkTime (ToTime Id))) "2020-07-11 11:41:12.333 CET"
+-- PresentT ((2020,7,11),(11,41,12333 % 1000))
+--
 data UnMkTime p
 
 instance (PP p x ~ TimeOfDay, P p x) => P (UnMkTime p) x where
@@ -2228,8 +2289,8 @@ -- >>> pz @(Rescan "^Date\\((\\d+)([^\\)]+)\\)" Id >> Head Id >> Snd Id >> ((ReadP Integer (Id !! 0) >> PosixToUTCTime (Id % 1000)) &&& ReadP TimeZone (Id !! 1))) "Date(1530144000000+0530)"
 -- PresentT (2018-06-28 00:00:00 UTC,+0530)
 --
--- not so uesful: just use ParseTimeP FormatTimeP with %s %q %z etc
-
+-- not so useful: instead use ParseTimeP FormatTimeP with %s %q %z etc
+--
 -- >>> pz @(ParseTimeP ZonedTime "%s%Q%z" Id)  "153014400.000+0530"
 -- PresentT 1974-11-07 05:30:00 +0530
 --
@@ -3520,7 +3581,7 @@   type PP (p * q) x = PP (MultT p q) x
   eval _ = eval (Proxy @(MultT p q))
 
--- | similar to '(^)'
+-- | similar to 'GHC.Real.(^)'
 --
 -- >>> pz @(Fst Id ^ Snd Id) (10,4)
 -- PresentT 10000
@@ -3551,7 +3612,7 @@                    else let d = p ^ q
                         in mkNode opts (PresentT d) (show p <> " ^ " <> show q <> " = " <> show d) hhs
 
--- | similar to '(**)'
+-- | similar to 'GHC.Float.(**)'
 --
 -- >>> pz @(Fst Id ** Snd Id) (10,4)
 -- PresentT 10000.0
@@ -4548,9 +4609,6 @@         let b = p > 1 && isPrime (fromIntegral p)
         in mkNodeB opts b (msg0 <> show1 opts " | " p) [hh pp]
 
-isPrime :: Word -> Bool
-isPrime n = n==2 || n>2 && all ((> 0).rem n) (2:[3,5 .. floor . sqrt @Double . fromIntegral $ n+1])
-
 -- | get the next prime number
 --
 -- >>> pz @(PrimeNext Id) 6
@@ -4566,7 +4624,7 @@         , Show a
         , Integral a
         ) => P (PrimeNext p) x where
-  type PP (PrimeNext p) x = Word
+  type PP (PrimeNext p) x = Int
   eval _ opts x = do
     let msg0 = "PrimeNext"
     pp <- eval (Proxy @p) opts x
@@ -5894,6 +5952,9 @@ -- >>> pz @(EnumFromTo (Pred Id) (Succ Id)) (SG.Max 10)
 -- PresentT [Max {getMax = 9},Max {getMax = 10},Max {getMax = 11}]
 --
+-- >>> pz @(EnumFromTo 1 20 >> Map '(Id, (If (Id `Mod` 3 == 0) "Fizz" "" <> If (Id `Mod` 5 == 0) "Buzz" "" )) Id) 123
+-- PresentT [(1,""),(2,""),(3,"Fizz"),(4,""),(5,"Buzz"),(6,"Fizz"),(7,""),(8,""),(9,"Fizz"),(10,"Buzz"),(11,""),(12,"Fizz"),(13,""),(14,""),(15,"FizzBuzz"),(16,""),(17,""),(18,"Fizz"),(19,""),(20,"Buzz")]
+--
 data EnumFromTo p q
 
 instance (P p x
@@ -5911,6 +5972,38 @@       Left e -> e
       Right (p,q,pp,qq) -> mkNode opts (PresentT (enumFromTo p q)) (msg0 <> " [" <> show p <> " .. " <> show q <> "]") [hh pp, hh qq]
 
+-- | similar to 'enumFromThenTo'
+--
+-- >>> pz @(EnumFromThenTo (ToEnum Day 10) (ToEnum Day 20) (ToEnum Day 70)) ()
+-- PresentT [1858-11-27,1858-12-07,1858-12-17,1858-12-27,1859-01-06,1859-01-16,1859-01-26]
+--
+-- >>> pz @(EnumFromThenTo (ReadP Day "2020-01-12") (ReadP Day "2020-02-12") (ReadP Day "2020-08-12")) ()
+-- PresentT [2020-01-12,2020-02-12,2020-03-14,2020-04-14,2020-05-15,2020-06-15,2020-07-16]
+--
+data EnumFromThenTo p q r
+
+instance (P p x
+        , P q x
+        , P r x
+        , PP p x ~ a
+        , Show a
+        , PP q x ~ a
+        , PP r x ~ a
+        , Enum a
+        ) => P (EnumFromThenTo p q r) x where
+  type PP (EnumFromThenTo p q r) x = [PP p x]
+  eval _ opts z = do
+    let msg0 = "EnumFromThenTo"
+    lr <- runPQ msg0 (Proxy @p) (Proxy @q) opts z []
+    case lr of
+      Left e -> pure e
+      Right (p,q,pp,qq) -> do
+        rr <- eval (Proxy @r) opts z
+        pure $ case getValueLR opts (msg0 ++ " r failed") rr [hh pp, hh qq] of
+          Left e -> e
+          Right r ->
+            mkNode opts (PresentT (enumFromThenTo p q r)) (msg0 <> " [" <> show p <> ", " <> show q <> " .. " <> show r <> "]") [hh pp, hh qq, hh rr]
+
 -- | similar to 'partitionEithers'
 --
 -- >>> pz @PartitionEithers [Left 'a',Right 2,Left 'c',Right 4,Right 99]
@@ -6063,9 +6156,6 @@ -- >>> pz @(Unfoldr (MaybeBool (Not Null) (SplitAt 2 Id)) Id) [1..5]
 -- PresentT [[1,2],[3,4],[5]]
 --
--- >>> pz @(IterateN 4 (Succ Id)) 4
--- PresentT [4,5,6,7]
---
 data Unfoldr p q
 --type IterateN (t :: Type) n f = Unfoldr (If (Fst Id == 0) (MkNothing t) (Snd Id &&& (Pred Id *** f) >> MkJust Id)) '(n, Id)
 
@@ -6107,6 +6197,14 @@ type family UnfoldT mbs where
   UnfoldT (Maybe (b,s)) = b
 
+-- | like 'iterate' but for a fixed number of elements
+--
+-- >>> pz @(IterateN 4 (Succ Id)) 4
+-- PresentT [4,5,6,7]
+--
+-- >>> pz @('(0,1) >> IterateN 20 '(Snd Id, Fst Id + Snd Id) >> Map (Fst Id) Id) "sdf"
+-- PresentT [0,1,1,2,3,5,8,13,21,34,55,89,144,233,377,610,987,1597,2584,4181]
+--
 data IterateN n f
 type IterateNT n f = Unfoldr (MaybeBool (Fst Id > 0) '(Snd Id, Pred Id *** f)) '(n, Id)
 
@@ -6185,6 +6283,10 @@ --
 -- >>> pz @(If (Gt 4) "greater than 4" "less than or equal to 4") 0
 -- PresentT "less than or equal to 4"
+--
+-- >>> pz @(If (Snd Id == "a") '("xxx",Fst Id + 13) (If (Snd Id == "b") '("yyy",Fst Id + 7) (Failt _ "oops"))) (99,"b")
+-- PresentT ("yyy",106)
+--
 data If p q r
 
 instance (Show (PP r a)
@@ -6446,6 +6548,9 @@ -- >>> pz @(Catch' (Succ Id) (Second (ShowP Id) >> PrintT "%s %s" Id)) LT
 -- PresentT EQ
 --
+-- >>> pz @(Len > 1 && Catch (Id !! 3 == 66) 'False) [1,2]
+-- FalseT
+--
 -- more flexible: takes a (String,x) and a proxy so we can still call 'False 'True
 -- now takes the FailT string and x so you can print more detail if you want
 -- need the proxy so we can fail without having to explicitly specify a type
@@ -7186,6 +7291,45 @@                   (False, False) -> topMessage pp <> " " <> msg0 <> " " <> topMessage qq
         in mkNodeB opts (p&&q) (show p <> " " <> msg0 <> " " <> show q <> (if null zz then zz else " | " <> zz)) [hh pp, hh qq]
 
+-- | short circuit version of boolean And
+--
+-- >>> pl @(Id > 10 &&~ Failt _ "ss") 9
+-- False (False &&~ ... | (9 > 10))
+-- FalseT
+--
+-- >>> pl @(Id > 10 &&~ Id == 12) 11
+-- False (True &&~ False | (11 == 12))
+-- FalseT
+--
+-- >>> pl @(Id > 10 &&~ Id == 11) 11
+-- True (True &&~ True)
+-- TrueT
+--
+data p &&~ q
+infixr 3 &&~
+
+instance (P p a
+        , P q a
+        , PP p a ~ Bool
+        , PP q a ~ Bool
+        ) => P (p &&~ q) a where
+  type PP (p &&~ q) a = Bool
+  eval _ opts a = do
+    let msg0 = "&&~"
+    pp <- eval (Proxy @p) opts a
+    case getValueLR opts msg0 pp [] of
+      Left e -> pure e
+      Right False ->
+        pure $ mkNodeB opts False ("False" <> " " <> msg0 <> " ... | " <> topMessage pp) [hh pp]
+      Right True -> do
+        qq <- eval (Proxy @q) opts a
+        pure $ case getValueLR opts msg0 qq [hh pp] of
+          Left e -> e
+          Right q ->
+            let zz = if q then ""
+                     else " | " <> topMessage qq
+            in mkNodeB opts q ("True" <> " " <> msg0 <> " " <> show q <> zz) [hh pp, hh qq]
+
 -- | similar to 'Prelude.||'
 --
 -- >>> pz @(Fst Id || (Length (Snd Id) >= 4)) (False,[11,12,13,14])
@@ -7210,10 +7354,48 @@       Left e -> e
       Right (p,q,pp,qq) ->
         let zz = case (p,q) of
-                  (False,False) -> topMessage pp <> " " <> msg0 <> " " <> topMessage qq
+                  (False,False) -> " | " <> topMessage pp <> " " <> msg0 <> " " <> topMessage qq
                   _ -> ""
-        in mkNodeB opts (p||q) (show p <> " " <> msg0 <> " " <> show q <> (if null zz then zz else " | " <> zz)) [hh pp, hh qq]
+        in mkNodeB opts (p||q) (show p <> " " <> msg0 <> " " <> show q <> zz) [hh pp, hh qq]
 
+-- | short circuit version of boolean Or
+--
+-- >>> pl @(Id > 10 ||~ Failt _ "ss") 11
+-- True (True ||~ ...)
+-- TrueT
+--
+-- >>> pz @(Id > 10 ||~ Id == 9) 9
+-- TrueT
+--
+-- >>> pl @(Id > 10 ||~ Id > 9) 9
+-- False (False ||~ False | (9 > 10) ||~ (9 > 9))
+-- FalseT
+--
+data p ||~ q
+infixr 2 ||~
+
+instance (P p a
+        , P q a
+        , PP p a ~ Bool
+        , PP q a ~ Bool
+        ) => P (p ||~ q) a where
+  type PP (p ||~ q) a = Bool
+  eval _ opts a = do
+    let msg0 = "||~"
+    pp <- eval (Proxy @p) opts a
+    case getValueLR opts msg0 pp [] of
+      Left e -> pure e
+      Right False -> do
+        qq <- eval (Proxy @q) opts a
+        pure $ case getValueLR opts msg0 qq [hh pp] of
+          Left e -> e
+          Right q ->
+            let zz = if q then ""
+                     else " | " <> topMessage pp <> " " <> msg0 <> " " <> topMessage qq
+            in mkNodeB opts q ("False" <> " " <> msg0 <> " " <> show q <> zz) [hh pp, hh qq]
+      Right True ->
+        pure $ mkNodeB opts True ("True" <> " " <> msg0 <> " ...") [hh pp]
+
 -- | implication
 --
 -- >>> pz @(Fst Id ~> (Length (Snd Id) >= 4)) (True,[11,12,13,14])
@@ -8392,6 +8574,15 @@ --
 -- >>> pz @(Case (FailS "asdf" >> Snd Id >> Unproxy) '[Lt 4,Lt 10,Same 50] '[PrintF "%d is lt4" Id, PrintF "%d is lt10" Id, PrintF "%d is same50" Id] Id) 99
 -- FailT "asdf"
+--
+-- >>> pz @(Case (Failt _ "x") '[Same "a",Same "b"] '["hey","there"] Id) "b"
+-- PresentT "there"
+--
+-- >>> pz @(Case (Failt _ "x") '[Id == "a",Id == "b"] '["hey","there"] Id) "a"
+-- PresentT "hey"
+--
+-- >>> pz @(Case (Failt _ "x") '[Same "a",Same "b"] '["hey","there"] Id) "c"
+-- FailT "x"
 --
 data CaseImpl (n :: Nat) (e :: k0) (ps :: [k]) (qs :: [k1]) (r :: k2)
 -- ps = conditions
src/Predicate/Refined.hs view
@@ -31,8 +31,6 @@     Refined
   , unRefined
   , RefinedC
-  , newRefined
-  , newRefinedM
   , RefinedT(..)
 
   -- ** print methods
@@ -40,6 +38,8 @@   , prtRefinedTIO
 
   -- ** create methods
+  , newRefined
+  , newRefinedM
   , withRefinedT
   , withRefinedTIO
   , newRefinedT
@@ -98,7 +98,7 @@ -- Right (Refined 13)
 --
 -- >>> prtRefinedIO @'OZ @(Between 10 14 Id) 99
--- Left FalseP
+-- Left FalseT
 --
 -- >>> prtRefinedIO @'OZ @(Last Id >> Len == 4) ["one","two","three","four"]
 -- Right (Refined ["one","two","three","four"])
@@ -107,37 +107,38 @@ -- Right (Refined "141.213.1.99")
 --
 -- >>> prtRefinedIO @'OZ @(Re "^\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}$" Id) "141.213.1"
--- Left FalseP
+-- Left FalseT
 --
 -- >>> prtRefinedIO @'OZ @(Map (ReadP Int Id) (Resplit "\\." Id) >> Guard (PrintF "bad length: found %d" Len) (Len == 4) >> 'True) "141.213.1"
--- Left (FailP "bad length: found 3")
+-- Left (FailT "bad length: found 3")
 --
 -- >>> prtRefinedIO @'OZ @(Map (ReadP Int Id) (Resplit "\\." Id) >> Guard (PrintF "bad length: found %d" Len) (Len == 4) >> GuardsN (PrintT "octet %d out of range %d" Id) 4 (Between 0 255 Id) >> 'True) "141.213.1.444"
--- Left (FailP "octet 3 out of range 444")
+-- Left (FailT "octet 3 out of range 444")
 --
 -- >>> prtRefinedIO @'OZ @(Map (ReadP Int Id) (Resplit "\\." Id) >> Guard (PrintF "bad length: found %d" Len) (Len == 4) >> GuardsN (PrintT "octet %d out of range %d" Id) 4 (Between 0 255 Id) >> 'True) "141.213.1x34.444"
--- Left (FailP "ReadP Int (1x34)")
+-- Left (FailT "ReadP Int (1x34)")
 --
 -- >>> prtRefinedIO @'OZ @(Map ('[Id] >> ReadP Int Id) Id >> Luhn Id) "12344"
 -- Right (Refined "12344")
 --
 -- >>> prtRefinedIO @'OZ @(Map ('[Id] >> ReadP Int Id) Id >> Luhn Id) "12340"
--- Left FalseP
+-- Left FalseT
 --
 -- >>> prtRefinedIO @'OZ @(Any (Prime Id) Id) [11,13,17,18]
 -- Right (Refined [11,13,17,18])
 --
 -- >>> prtRefinedIO @'OZ @(All (Prime Id) Id) [11,13,17,18]
--- Left FalseP
+-- Left FalseT
 --
 -- >>> prtRefinedIO @'OZ @(Snd Id !! Fst Id >> Len > 5) (2,["abc","defghij","xyzxyazsfd"])
 -- Right (Refined (2,["abc","defghij","xyzxyazsfd"]))
 --
 -- >>> prtRefinedIO @'OZ @(Snd Id !! Fst Id >> Len > 5) (27,["abc","defghij","xyzxyazsfd"])
--- Left (FailP "(!!) index not found")
+-- Left (FailT "(!!) index not found")
 --
 -- >>> prtRefinedIO @'OZ @(Snd Id !! Fst Id >> Len <= 5) (2,["abc","defghij","xyzxyazsfd"])
--- Left FalseP
+-- Left FalseT
+--
 newtype Refined (opts :: OptT) p a = Refined a deriving (Show, Eq, Generic, TH.Lift)
 
 -- | extract the value from Refined
@@ -146,6 +147,14 @@ 
 type role Refined nominal nominal nominal
 
+-- | 'IsString' instance for Refined
+--
+-- >>> pureTryTest $ fromString @(Refined 'OL (ReadP Int Id >> Id > 244) String) "523"
+-- Right (Refined "523")
+--
+-- >>> pureTryTest $ fromString @(Refined 'OL (ReadP Int Id >> Id > 244) String) "52"
+-- Left ()
+--
 instance RefinedC opts p String => IsString (Refined opts p String) where
   fromString s =
     let (w,mr) = runIdentity $ newRefinedM @opts @p s
@@ -258,10 +267,23 @@          ) => Hashable (Refined opts p a) where
   hashWithSalt s (Refined a) = s + hash a
 
-instance (Arbitrary a, RefinedC opts p a, Show a) => Arbitrary (Refined opts p a) where
+-- | 'Arbitrary' instance for 'Refined'
+--
+-- >>> xs <- generate (vectorOf 10 (arbitrary @(Refined 'OU (Id /= 0) Int)))
+-- >>> all ((/=0) . unRefined) xs
+-- True
+--
+-- >>> xs <- generate (vectorOf 10 (arbitrary @(Refined 'OU (Prime Id) Int)))
+-- >>> all (isPrime . unRefined) xs
+-- True
+--
+instance ( Arbitrary a
+         , RefinedC opts p a
+         , Show a
+         ) => Arbitrary (Refined opts p a) where
   arbitrary = genRefined arbitrary
 
--- | 'arbitrary' value for 'Refined'
+-- | create 'Refined' generator using a generator to restrict the values
 genRefined :: forall opts p a .
    RefinedC opts p a
    => Gen a
@@ -273,7 +295,7 @@         case ma of
           Nothing ->
              if cnt >= oRecursion o
-             then error $ markBoundary o ("genRefined recursion exceeded(" ++ show (oRecursion o) ++ ")")
+             then error $ setOtherEffects o ("genRefined recursion exceeded(" ++ show (oRecursion o) ++ ")")
              else f (cnt+1)
           Just a -> pure $ unsafeRefined a
   in f 0
@@ -286,11 +308,11 @@   -> RefinedT m (Refined opts p a)
 rapply f ma mb = do
   let opts = getOptT @opts
-  tell [markBoundary opts "=== a ==="]
+  tell [setOtherEffects opts "=== a ==="]
   Refined x <- ma
-  tell [markBoundary opts "=== b ==="]
+  tell [setOtherEffects opts "=== b ==="]
   Refined y <- mb
-  tell [markBoundary opts "=== a `op` b ==="]
+  tell [setOtherEffects opts "=== a `op` b ==="]
   newRefinedT @m @opts @p (f x y)
 
 -- | takes two values and lifts them into 'RefinedT' and then applies the binary operation
@@ -345,18 +367,18 @@ prtRefinedIO :: forall opts p a
    . RefinedC opts p a
    => a
-   -> IO (Either BoolP (Refined opts p a))
+   -> IO (Either (BoolT Bool) (Refined opts p a))
 prtRefinedIO a = do
   let o = getOptT @opts
   tt <- evalBool (Proxy @p) o a
-  let msg = (_tBool tt ^. boolT2P, prtTree' o tt) -- (fromTT tt))
+  let r = _tBool tt
   case oDebug o of
-     DZero -> pure ()  -- putStrLn $ colorBoolP opts (fst msg) <> " " <> topMessage tt
-     DLite -> putStrLn $ colorBoolT' o (_tBool tt) <> " " <> topMessage tt
-     _ -> putStrLn $ snd msg
+     DZero -> pure ()
+     DLite -> putStrLn $ colorBoolT o r <> " " <> topMessage tt
+     _ -> putStrLn $ prtTree o tt
   pure $ case getValueLR o "" tt [] of
     Right True -> Right (Refined a)
-    _ -> Left (fst msg)
+    _ -> Left r
 
 -- | returns a 'Refined' value if \'a\' is valid for the predicate \'p\'
 --
@@ -388,8 +410,8 @@ newRefinedM a = do
   let o = getOptT @opts
   pp <- evalBool (Proxy @p) o a
-  let r = colorBoolT o (_tBool pp)
-      s = prtTree' o pp
+  let r = colorBoolT' o (_tBool pp)
+      s = prtTree o pp
   pure $ ((r,(topMessage pp, s)),) $ case getValueLR o "" pp [] of
        Right True -> Just (Refined a)
        _ -> Nothing
@@ -405,11 +427,11 @@ newRefinedTImpl f a = do
   let o = getOptT @opts
   tt <- f $ evalBool (Proxy @p) o a
-  let msg = prtTree' o tt
+  let msg = prtTree o tt
   tell [msg]
   case getValueLR o "" tt [] of
     Right True -> return (Refined a) -- FalseP is also a failure!
-    _ -> throwError $ colorBoolT o (_tBool tt)
+    _ -> throwError $ colorBoolT' o (_tBool tt)
 
 -- | returns a wrapper 'RefinedT' around a possible 'Refined' value if \'a\' is valid for the predicate \'p\'
 newRefinedT :: forall m opts p a
@@ -475,11 +497,12 @@       tt = runIdentity $ evalBool (Proxy @p) o a
   in case getValueLR o "" tt [] of
        Right True -> Refined a
-       _ -> let s = prtTree' o tt
+       _ -> let s = prtTree o tt
+                bp = colorBoolT' o (view tBool tt)
             in case oDebug o of
-                 DZero -> error $ colorBoolT' o (view tBool tt)
-                 DLite -> error s
-                 _ -> error $ "\n" ++ s
+                 DZero -> error bp
+                 DLite -> error $ bp ++ "\n" ++ s
+                 _ -> error $ bp ++ "\n" ++ s
 
 type family ReplaceOptT (o :: OptT) t where
   ReplaceOptT o (Refined _ p a) = Refined o p a
src/Predicate/Refined1.hs view
@@ -100,6 +100,7 @@ import Data.Functor.Identity (Identity(..))
 import Data.Tree
 import Data.Proxy
+import Control.Arrow (left)
 import Control.Monad.Except
 import Control.Monad.Writer (tell)
 import Data.Aeson (ToJSON(..), FromJSON(..))
@@ -219,6 +220,14 @@ deriving instance (Eq i, Eq (PP ip i), Eq (PP fmt (PP ip i))) => Eq (Refined1 opts ip op fmt i)
 deriving instance (TH.Lift (PP ip i), TH.Lift (PP fmt (PP ip i))) => TH.Lift (Refined1 opts ip op fmt i)
 
+-- | 'IsString' instance for Refined1
+--
+-- >>> pureTryTest $ fromString @(Refined1 'OL (ReadP Int Id) (Id > 12) (ShowP Id) String) "523"
+-- Right (Refined1 523)
+--
+-- >>> pureTryTest $ fromString @(Refined1 'OL (ReadP Int Id) (Id > 12) (ShowP Id) String) "2"
+-- Left ()
+--
 instance (Refined1C opts ip op fmt String, Show (PP ip String)) => IsString (Refined1 opts ip op fmt String) where
   fromString s =
     let (ret,mr) = eval1 @opts @ip @op @fmt s
@@ -333,13 +342,28 @@                   case mr of
                     Nothing -> fail $ "Refined1:" ++ show (prt1Impl (getOptT @opts) ret)
                     Just r -> return r
-
+-- | 'Arbitrary' instance for 'Refined1'
+--
+-- >>> xs <- generate (vectorOf 10 (arbitrary @(Refined1 'OU (ReadP Int Id) (1 <..> 120 && Even) (ShowP Id) String)))
+-- >>> all ((/=0) . unRefined1) xs
+-- True
+--
+-- >>> xs <- generate (vectorOf 10 (arbitrary @(Refined1 'OU Id (Prime Id) Id Int)))
+-- >>> all (isPrime . unRefined1) xs
+-- True
+--
 instance (Arbitrary (PP ip i)
         , Refined1C opts ip op fmt i
         ) => Arbitrary (Refined1 opts ip op fmt i) where
   arbitrary = genRefined1 arbitrary
 
 -- | create a 'Refined1' generator
+--
+-- >>> g = genRefined1 @'OU @(ReadP Int Id) @(Between 10 100 Id && Even) @(ShowP Id) (choose (10,100))
+-- >>> xs <- generate (vectorOf 10 g)
+-- >>> all (\x -> let y = unRefined1 x in y >= 0 && y <= 100 && even y) xs
+-- True
+--
 genRefined1 ::
     forall opts ip op fmt i
   . Refined1C opts ip op fmt i
@@ -347,7 +371,7 @@   -> Gen (Refined1 opts ip op fmt i)
 genRefined1 = genRefined1P Proxy
 
--- | create a 'Refined1' generator
+-- | create a 'Refined1' generator with a Proxy
 genRefined1P ::
     forall opts ip op fmt i
   . Refined1C opts ip op fmt i
@@ -361,7 +385,7 @@         case mppi of
           Nothing ->
              if cnt >= oRecursion o
-             then error $ markBoundary o ("genRefined1 recursion exceeded(" ++ show (oRecursion o) ++ ")")
+             then error $ setOtherEffects o ("genRefined1 recursion exceeded(" ++ show (oRecursion o) ++ ")")
              else f (cnt+1)
           Just ppi ->
              pure $ unsafeRefined1 ppi
@@ -525,13 +549,13 @@ 
 -- | pure version for extracting Refined1
 --
--- >>> newRefined1 @'OU @(ParseTimeP TimeOfDay "%-H:%-M:%-S" Id) @'True @(FormatTimeP "%H:%M:%S" Id) "1:15:7"
+-- >>> newRefined1 @'OL @(ParseTimeP TimeOfDay "%-H:%-M:%-S" Id) @'True @(FormatTimeP "%H:%M:%S" Id) "1:15:7"
 -- Right (Refined1 01:15:07)
 --
--- >>> newRefined1 @'OU @(ParseTimeP TimeOfDay "%-H:%-M:%-S" Id) @'True @(FormatTimeP "%H:%M:%S" Id) "1:2:x"
+-- >>> newRefined1 @'OL @(ParseTimeP TimeOfDay "%-H:%-M:%-S" Id) @'True @(FormatTimeP "%H:%M:%S" Id) "1:2:x"
 -- Left "Step 1. Initial Conversion(ip) Failed | ParseTimeP TimeOfDay (%-H:%-M:%-S) failed to parse"
 --
--- >>> newRefined1 @'OU @(Rescan "^(\\d{1,2}):(\\d{1,2}):(\\d{1,2})$" Id >> Snd (Head Id) >> Map (ReadP Int Id) Id) @(All (0 <..> 59) Id && Len == 3) @(PrintL 3 "%02d:%02d:%02d" Id) "1:2:3"
+-- >>> newRefined1 @'OL @(Rescan "^(\\d{1,2}):(\\d{1,2}):(\\d{1,2})$" Id >> Snd (Head Id) >> Map (ReadP Int Id) Id) @(All (0 <..> 59) Id && Len == 3) @(PrintL 3 "%02d:%02d:%02d" Id) "1:2:3"
 -- Right (Refined1 [1,2,3])
 --
 newRefined1 :: forall opts ip op fmt i
@@ -551,7 +575,9 @@    => proxy '(opts,ip,op,fmt,i)
    -> i
    -> Either String (Refined1 opts ip op fmt i)
-newRefined1P _ = fst . runIdentity . unRavelT . newRefined1T @_ @opts @ip @op @fmt
+newRefined1P _ x =
+  let (lr,xs) = runIdentity $ unRavelT $ newRefined1T @_ @opts @ip @op @fmt x
+  in left (\e -> e ++ (if all null xs then "" else "\n" ++ unlines xs)) lr
 
 newRefined1T :: forall m opts ip op fmt i
   . ( Refined1C opts ip op fmt i
@@ -675,12 +701,12 @@   -> RefinedT m (Refined1 opts ip op fmt i)
 rapply1P p f ma mb = do
   let opts = getOptT @opts
-  tell [markBoundary opts "=== a ==="]
+  tell [setOtherEffects opts "=== a ==="]
   Refined1 x <- ma
-  tell [markBoundary opts "=== b ==="]
+  tell [setOtherEffects opts "=== b ==="]
   Refined1 y <- mb
   -- we skip the input value @Id and go straight to the internal value so PP fmt (PP ip i) /= i for this call
-  tell [markBoundary opts "=== a `op` b ==="]
+  tell [setOtherEffects opts "=== a `op` b ==="]
   Refined1 a <- newRefined1TPSkipIPImpl (return . runIdentity) p (f x y)
   return (Refined1 a)
 
src/Predicate/Refined2.hs view
@@ -3,6 +3,7 @@ {-# OPTIONS -Wincomplete-record-updates #-}
 {-# OPTIONS -Wincomplete-uni-patterns #-}
 {-# OPTIONS -Wno-redundant-constraints #-}
+{-# LANGUAGE BangPatterns #-}
 {-# LANGUAGE TypeOperators #-}
 {-# LANGUAGE UndecidableInstances #-}
 {-# LANGUAGE FlexibleContexts #-}
@@ -62,6 +63,10 @@   , mkProxy2
   , mkProxy2'
 
+  -- ** QuickCheck methods
+  , genRefined2
+  , genRefined2P
+
   -- ** unsafe methods for creating Refined2
   , unsafeRefined2
   , unsafeRefined2'
@@ -76,6 +81,7 @@ import Data.Functor.Identity (Identity(..))
 import Data.Tree
 import Data.Proxy
+import Control.Arrow (left)
 import Control.Monad.Except
 import Control.Monad.Writer (tell)
 import Data.Aeson (ToJSON(..), FromJSON(..))
@@ -85,13 +91,14 @@ import qualified Text.Read.Lex as RL
 import qualified Data.Binary as B
 import Data.Binary (Binary)
-import Data.Maybe (fromMaybe)
-import Control.Lens ((^.))
+import Data.Maybe (fromMaybe, isJust)
+import Control.Lens
 import Data.Tree.Lens (root)
 import Data.Char (isSpace)
 import Data.String
 import Data.Hashable (Hashable(..))
 import GHC.Stack
+import Test.QuickCheck
 
 -- $setup
 -- >>> :set -XDataKinds
@@ -170,6 +177,14 @@ deriving instance (Eq i, Eq (PP ip i)) => Eq (Refined2 opts ip op i)
 deriving instance (TH.Lift (PP ip i), TH.Lift i) => TH.Lift (Refined2 opts ip op i)
 
+-- | 'IsString' instance for Refined2
+--
+-- >>> pureTryTest $ fromString @(Refined2 'OL (ReadP Int Id) (Id > 12) String) "523"
+-- Right (Refined2 {r2In = 523, r2Out = "523"})
+--
+-- >>> pureTryTest $ fromString @(Refined2 'OL (ReadP Int Id) (Id > 12) String) "2"
+-- Left ()
+--
 instance ( s ~ String
          , Refined2C opts ip op s
          , Show (PP ip s)
@@ -279,11 +294,64 @@                     Nothing -> fail $ "Refined2:" ++ show (prt2Impl (getOptT @opts) ret)
                     Just r -> return r
 
+-- | 'Arbitrary' instance for 'Refined2'
+--
+-- >>> :m + Data.Time.Calendar.WeekDate
+-- >>> xs <- generate (vectorOf 10 (arbitrary @(Refined2 'OU (ToEnum Day Id) (Snd (ToWeekDate Id) == "Tuesday") Int)))
+-- >>> all (\x -> let y = toEnum @Day (r2Out x) in view _3 (toWeekDate y) == 2 && r2In x == y) xs
+-- True
+--
+instance ( Arbitrary i
+         , Refined2C opts ip op i
+         , Show (PP ip i)
+         ) => Arbitrary (Refined2 opts ip op i) where
+  arbitrary = genRefined2 arbitrary
 
+-- | create a 'Refined2' generator using a generator to restrict the values (so it completes)
+--
+-- >>> g = genRefined2 @'OU @(ToEnum Day Id) @(UnMkDay Id >> Snd Id == 10) arbitrary
+-- >>> xs <- generate (vectorOf 10 g)
+-- >>> all (\x -> let y = toEnum @Day (fromIntegral (r2Out x)) in view _2 (toGregorian y) == 10 && y == r2In x) xs
+-- True
+--
+genRefined2 ::
+    forall opts ip op i
+  . ( Refined2C opts ip op i
+    , Show (PP ip i)
+    )
+  => Gen i
+  -> Gen (Refined2 opts ip op i)
+genRefined2 = genRefined2P Proxy
+
+-- generates the external value unlike Refined3 as we dont have a way to recreate the output from the internal value
+-- | create a 'Refined2' generator using a proxy
+genRefined2P ::
+    forall opts ip op i
+  . ( Refined2C opts ip op i
+    , Show (PP ip i)
+    )
+  => Proxy '(opts,ip,op,i)
+  -> Gen i
+  -> Gen (Refined2 opts ip op i)
+genRefined2P _ g =
+  let o = getOptT @opts
+      f !cnt = do
+        mi <- suchThatMaybe g (isJust . snd . eval2 @opts @ip @op)
+        case mi of
+          Nothing ->
+             if cnt >= oRecursion o
+             then error $ setOtherEffects o ("genRefined2P recursion exceeded(" ++ show (oRecursion o) ++ ")")
+             else f (cnt+1)
+          Just i -> do
+             let lr = newRefined2 @opts @ip @op i
+             case lr of
+               Left e -> error $ "conversion failed: programming error failed!! " ++ e
+               Right r -> pure r
+  in f 0
+
 -- | 'Binary' instance for 'Refined2'
 --
 -- >>> import Control.Arrow ((+++))
--- >>> import Control.Lens
 -- >>> import Data.Time
 -- >>> type K1 = Refined2 'OAN (ReadP Day Id) 'True String
 -- >>> type K2 = Refined2 'OAN (ReadP Day Id) (Between (ReadP Day "2019-05-30") (ReadP Day "2019-06-01") Id) String
@@ -399,13 +467,13 @@ 
 -- | pure version for extracting Refined2
 --
--- >>> newRefined2 @'OU @Id @'True 22
+-- >>> newRefined2 @'OL @Id @'True 22
 -- Right (Refined2 {r2In = 22, r2Out = 22})
 --
--- >>> newRefined2 @'OU @(ReadP UTCTime Id) @(Between (MkDay '(2020,5,2)) (MkDay '(2020,5,7)) (MkJust (ToDay Id))) "2020-05-04 12:13:14Z"
+-- >>> newRefined2 @'OL @(ReadP UTCTime Id) @(Between (MkDay '(2020,5,2)) (MkDay '(2020,5,7)) (MkJust (ToDay Id))) "2020-05-04 12:13:14Z"
 -- Right (Refined2 {r2In = 2020-05-04 12:13:14 UTC, r2Out = "2020-05-04 12:13:14Z"})
 --
--- >>> newRefined2 @'OU @(ReadP UTCTime Id) @(Between (MkDay '(2020,5,2)) (MkDay '(2020,5,7)) (MkJust (ToDay Id))) "2020-05-08 12:13:14Z"
+-- >>> newRefined2 @'OL @(ReadP UTCTime Id) @(Between (MkDay '(2020,5,2)) (MkDay '(2020,5,7)) (MkJust (ToDay Id))) "2020-05-08 12:13:14Z"
 -- Left "Step 2. False Boolean Check(op) | {Just 2020-05-08 <= Just 2020-05-07}"
 --
 newRefined2 :: forall opts ip op i
@@ -421,7 +489,9 @@     ) => proxy '(opts,ip,op,i)
       -> i
       -> Either String (Refined2 opts ip op i)
-newRefined2P _ = fst . runIdentity . unRavelT . newRefined2T @_ @opts @ip @op
+newRefined2P _ x =
+  let (lr,xs) = runIdentity $ unRavelT $ newRefined2T @_ @opts @ip @op x
+  in left (\e -> e ++ (if all null xs then "" else "\n" ++ unlines xs)) lr
 
 -- | create a wrapped 'Refined2' type
 --
src/Predicate/Refined3.hs view
@@ -99,6 +99,7 @@ import Data.Functor.Identity (Identity(..))
 import Data.Tree
 import Data.Proxy
+import Control.Arrow (left)
 import Control.Monad.Except
 import Control.Monad.Writer (tell)
 import Data.Aeson (ToJSON(..), FromJSON(..))
@@ -124,7 +125,7 @@ -- >>> :m + Predicate.Prelude
 -- >>> :m + Data.Time
 
--- | Like 'Refined2' but additionally reconstructs the output value to a standardized format
+-- | Like 'Predicate.Refined2' but additionally reconstructs the output value to a standardized format
 --
 --   * @opts@ are the display options
 --   * @ip@ converts @i@ to @PP ip i@ which is the internal type and stored in 'r3In'
@@ -216,6 +217,14 @@ deriving instance (Eq i, Eq (PP ip i), Eq (PP fmt (PP ip i))) => Eq (Refined3 opts ip op fmt i)
 deriving instance (TH.Lift (PP ip i), TH.Lift (PP fmt (PP ip i))) => TH.Lift (Refined3 opts ip op fmt i)
 
+-- | 'IsString' instance for Refined3
+--
+-- >>> pureTryTest $ fromString @(Refined3 'OL (ReadP Int Id) (Id > 12) (ShowP Id) String) "523"
+-- Right (Refined3 {r3In = 523, r3Out = "523"})
+--
+-- >>> pureTryTest $ fromString @(Refined3 'OL (ReadP Int Id) (Id > 12) (ShowP Id) String) "2"
+-- Left ()
+--
 instance (Refined3C opts ip op fmt String, Show (PP ip String))
   => IsString (Refined3 opts ip op fmt String) where
   fromString s =
@@ -326,12 +335,24 @@                     Nothing -> fail $ "Refined3:" ++ show (prt3Impl (getOptT @opts) ret)
                     Just r -> return r
 
+-- | 'Arbitrary' instance for 'Refined3'
+--
+-- >>> xs <- generate (vectorOf 10 (arbitrary @(Refined3 'OU (ReadP Int Id) (1 <..> 120 && Even) (ShowP Id) String)))
+-- >>> all (\x -> let y = r3In x in y /= 0 && r3Out x == show y) xs
+-- True
+--
 instance ( Arbitrary (PP ip i)
          , Refined3C opts ip op fmt i
          ) => Arbitrary (Refined3 opts ip op fmt i) where
   arbitrary = genRefined3 arbitrary
 
--- | create a 'Refined3' generator
+-- | create a 'Refined3' generator using a generator to restrict the values (so it completes)
+--
+-- >>> g = genRefined3 @'OU @(ReadP Int Id) @(Between 10 100 Id && Even) @(ShowP Id) (choose (10,100))
+-- >>> xs <- generate (vectorOf 10 g)
+-- >>> all (\x -> let y = r3In x in y >= 0 && y <= 100 && even y) xs
+-- True
+--
 genRefined3 ::
     forall opts ip op fmt i
   . Refined3C opts ip op fmt i
@@ -339,7 +360,7 @@   -> Gen (Refined3 opts ip op fmt i)
 genRefined3 = genRefined3P Proxy
 
--- | create a 'Refined3' generator
+-- | create a 'Refined3' generator using a proxy
 genRefined3P ::
     forall opts ip op fmt i
   . Refined3C opts ip op fmt i
@@ -353,7 +374,7 @@         case mppi of
           Nothing ->
              if cnt >= oRecursion o
-             then error $ markBoundary o ("genRefined3 recursion exceeded(" ++ show (oRecursion o) ++ ")")
+             then error $ setOtherEffects o ("genRefined3P recursion exceeded(" ++ show (oRecursion o) ++ ")")
              else f (cnt+1)
           Just ppi -> do
              let lr = getValLRFromTT (runIdentity (eval @_ (Proxy @fmt) o ppi))
@@ -516,13 +537,13 @@ 
 -- | pure version for extracting Refined3
 --
--- >>> newRefined3 @'OU @(ParseTimeP TimeOfDay "%-H:%-M:%-S" Id) @'True @(FormatTimeP "%H:%M:%S" Id) "1:15:7"
+-- >>> newRefined3 @'OL @(ParseTimeP TimeOfDay "%-H:%-M:%-S" Id) @'True @(FormatTimeP "%H:%M:%S" Id) "1:15:7"
 -- Right (Refined3 {r3In = 01:15:07, r3Out = "01:15:07"})
 --
--- >>> newRefined3 @'OU @(ParseTimeP TimeOfDay "%-H:%-M:%-S" Id) @'True @(FormatTimeP "%H:%M:%S" Id) "1:2:x"
+-- >>> newRefined3 @'OL @(ParseTimeP TimeOfDay "%-H:%-M:%-S" Id) @'True @(FormatTimeP "%H:%M:%S" Id) "1:2:x"
 -- Left "Step 1. Initial Conversion(ip) Failed | ParseTimeP TimeOfDay (%-H:%-M:%-S) failed to parse"
 --
--- >>> newRefined3 @'OU @(Rescan "^(\\d{1,2}):(\\d{1,2}):(\\d{1,2})$" Id >> Snd (Head Id) >> Map (ReadP Int Id) Id) @(All (0 <..> 59) Id && Len == 3) @(PrintL 3 "%02d:%02d:%02d" Id) "1:2:3"
+-- >>> newRefined3 @'OL @(Rescan "^(\\d{1,2}):(\\d{1,2}):(\\d{1,2})$" Id >> Snd (Head Id) >> Map (ReadP Int Id) Id) @(All (0 <..> 59) Id && Len == 3) @(PrintL 3 "%02d:%02d:%02d" Id) "1:2:3"
 -- Right (Refined3 {r3In = [1,2,3], r3Out = "01:02:03"})
 --
 newRefined3 :: forall opts ip op fmt i
@@ -542,7 +563,9 @@    => proxy '(opts,ip,op,fmt,i)
    -> i
    -> Either String (Refined3 opts ip op fmt i)
-newRefined3P _ = fst . runIdentity . unRavelT . newRefined3T @_ @opts @ip @op @fmt
+newRefined3P _ x =
+  let (lr,xs) = runIdentity $ unRavelT $ newRefined3T @_ @opts @ip @op @fmt x
+  in left (\e -> e ++ (if all null xs then "" else "\n" ++ unlines xs)) lr
 
 -- | create a wrapped 'Refined3' type
 --
@@ -679,12 +702,12 @@   -> RefinedT m (Refined3 opts ip op fmt i)
 rapply3P p f ma mb = do
   let opts = getOptT @opts
-  tell [markBoundary opts "=== a ==="]
+  tell [setOtherEffects opts "=== a ==="]
   Refined3 x _ <- ma
-  tell [markBoundary opts "=== b ==="]
+  tell [setOtherEffects opts "=== b ==="]
   Refined3 y _ <- mb
   -- we skip the input value @Id and go straight to the internal value so PP fmt (PP ip i) /= i for this call
-  tell [markBoundary opts "=== a `op` b ==="]
+  tell [setOtherEffects opts "=== a `op` b ==="]
   Refined3 a b <- newRefined3TPSkipIPImpl (return . runIdentity) p (f x y)
   return (Refined3 a b)
 
src/Predicate/Util.hs view
@@ -7,7 +7,6 @@ {-# LANGUAGE FlexibleContexts #-}
 {-# LANGUAGE AllowAmbiguousTypes #-}
 {-# LANGUAGE FlexibleInstances #-}
-{-# LANGUAGE MultiParamTypeClasses #-}
 {-# LANGUAGE TypeApplications #-}
 {-# LANGUAGE DataKinds #-}
 {-# LANGUAGE GADTs #-}
@@ -38,7 +37,6 @@ 
  -- ** BoolT
   , BoolT(..)
-  , BoolP
   , GetBoolT(..)
   , _FailT
   , _PresentT
@@ -46,11 +44,8 @@   , _TrueT
 
  -- ** BoolP
-  , boolT2P
---  , BoolP
-  , PE(PE)
+  , PE
   , pString
-  , pBool
 
  -- ** create tree functions
   , mkNode
@@ -74,17 +69,18 @@   , Debug(..)
   , Disp(..)
   , Color(..)
-  , markBoundary
   , colorMe
   , isVerbose
-  , colorBoolP
   , colorBoolT
   , colorBoolT'
+  , setOtherEffects
   , type Color1
   , type Color2
   , type Color3
   , type Color4
   , type Color5
+  , type Other1
+  , type Other2
 
   , HOpts(..)
   , OptT(..)
@@ -112,7 +108,7 @@   , compileRegex
   , GetROpts(..)
   , RReplace(..)
-  , ReplaceFnSubC(..)
+  , GetReplaceFnSub(..)
   , ReplaceFnSub(..)
 
   -- ** useful type families
@@ -150,9 +146,6 @@   , GetOrd(..)
 
  -- ** printing methods
-  , prtTTIO
-  , prtTT
-  , prtTree
   , prtTreePure
   , prettyRational
   , formatOMsg
@@ -160,6 +153,17 @@  -- ** boolean methods
   , (~>)
 
+  -- ** extract from n-tuple
+  , T4_1
+  , T4_2
+  , T4_3
+  , T4_4
+  , T5_1
+  , T5_2
+  , T5_3
+  , T5_4
+  , T5_5
+
  -- ** miscellaneous
   , Holder
   , hh
@@ -171,17 +175,9 @@   , readField
   , showThese
   , chkSize
-
-  -- ** extract from n-tuple
-  , T4_1
-  , T4_2
-  , T4_3
-  , T4_4
-  , T5_1
-  , T5_2
-  , T5_3
-  , T5_4
-  , T5_5
+  , pureTryTest
+  , pureTryTestPred
+  , isPrime
 
     ) where
 import qualified GHC.TypeNats as GN
@@ -207,6 +203,7 @@ import Control.Applicative (ZipList)
 import Data.Kind (Type)
 import Data.These (These(..))
+import Data.These.Combinators (isThis, isThat, isThese)
 import qualified Control.Exception as E
 import Control.DeepSeq
 import System.IO.Unsafe (unsafePerformIO)
@@ -223,7 +220,6 @@ import GHC.Stack
 import Data.Monoid (Last (..))
 import Data.Maybe
---import Data.Function (on)
 import Data.Coerce
 import Data.Foldable (toList)
 
@@ -239,18 +235,12 @@                } deriving Show
 
 -- | contains the typed result from evaluating the expression tree
---
 data BoolT a where
   FailT :: !String -> BoolT a  -- failure with string
   FalseT :: BoolT Bool        -- false predicate
   TrueT :: BoolT Bool         -- true predicate
   PresentT :: !a -> BoolT a    -- non predicate value
 
-{- too restrictive
-instance Semigroup a => Semigroup (BoolT a) where
-   PresentT a <> PresentT a1 = PresentT (a <> a1)
--}
-
 -- | semigroup instance for 'BoolT'
 --
 instance Semigroup (BoolT a) where
@@ -267,6 +257,7 @@ deriving instance Show a => Show (BoolT a)
 deriving instance Eq a => Eq (BoolT a)
 
+-- | extracts the 'BoolT a' constructors from the typelevel
 class GetBoolT a (x :: BoolT a) | x -> a where
   getBoolT :: Either Bool Bool
 instance GetBoolT Bool 'TrueT where
@@ -282,9 +273,11 @@ tBool :: Lens (TT a) (TT b) (BoolT a) (BoolT b)
 tBool afb s = (\b -> s { _tBool = b }) <$> afb (_tBool s)
 
+-- | lens for accessing the message from 'BoolT'
 tString :: Lens' (TT a) String
 tString afb s = (\b -> s { _tString = b }) <$> afb (_tString s)
 
+-- | lens for accessing the subtree from 'BoolT'
 tForest :: Lens' (TT a) (Forest PE)
 tForest afb s = (\b -> s { _tForest = b }) <$> afb (_tForest s)
 
@@ -309,9 +302,11 @@              , _pString :: !String -- ^ optional strings to include in the results
              } deriving Show
 
+-- | prism for accessing '_pBool'
 pBool :: Lens' PE BoolP
 pBool afb (PE x y) = flip PE y <$> afb x
 
+-- | prism for accessing 'PE'
 pString :: Lens' PE String
 pString afb s = (\b -> s { _pString = b }) <$> afb (_pString s)
 
@@ -381,18 +376,35 @@           )
           (getValLRFromTT tt)
 
+-- | wrapper for a show instance around 'Color'
+newtype SColor = SColor Color
+
+instance Show SColor where
+  show (SColor c) =
+    case c of
+      Black-> "Black"
+      Red-> "Red"
+      Green-> "Green"
+      Yellow-> "Yellow"
+      Blue-> "Blue"
+      Magenta-> "Magenta"
+      Cyan-> "Cyan"
+      White-> "White"
+      Default -> "Default"
+
 -- | the color palette for displaying the expression tree
 newtype PColor = PColor (BoolP -> String -> String)
 instance Show PColor where
   show PColor {} = "PColor <fn>"
 
+-- | elide the 'Identity' wrapper so it acts like a normal adt
 type family HKD f a where
   HKD Identity a = a
   HKD f a = f a
 
 type POpts = HOpts Identity
 
--- | customizable options
+-- | customizable options for running a typelevel expression
 data HOpts f =
   HOpts { oWidth :: !(HKD f Int) -- ^ length of data to display for 'showLitImpl'
         , oDebug :: !(HKD f Debug) -- ^ debug level
@@ -400,7 +412,7 @@         , oColor :: !(HKD f (String, PColor)) -- ^ color palette used
         , oMsg :: ![String] -- ^ messages associated with type
         , oRecursion :: !(HKD f Int) -- ^ max recursion
-        , oOther :: !(HKD f (Color, Color)) -- ^ other message effects
+        , oOther :: !(HKD f (Bool, SColor, SColor)) -- ^ other message effects
         , oNoColor :: !(HKD f Bool) -- ^ no colors
         }
 
@@ -410,9 +422,10 @@   , Show (HKD f Disp)
   , Show (HKD f (String, PColor))
   , Show (HKD f Bool)
-  , Show (HKD f (Color, Color))
+  , Show (HKD f (Bool, SColor, SColor))
   ) => Show (HOpts f)
 
+-- | combine options ala monoid
 reifyOpts :: HOpts Last -> HOpts Identity
 reifyOpts h =
   HOpts (fromMaybe (oWidth defOpts) (getLast (oWidth h)))
@@ -426,24 +439,31 @@          else fromMaybe (oOther defOpts) (getLast (oOther h)))
         (fromMaybe (oNoColor defOpts) (getLast (oNoColor h)))
 
+-- | set maximum display width of expressions
 setWidth :: Int -> POptsL
 setWidth i = mempty { oWidth = pure i }
 
+-- | set title message for the display tree
 setMessage :: String -> POptsL
 setMessage s = mempty { oMsg = pure s }
 
+-- | set maximum recursion eg when running regex
 setRecursion :: Int -> POptsL
 setRecursion i = mempty { oRecursion = pure i }
 
-setOther :: Color -> Color -> POptsL
-setOther c1 c2 = mempty { oOther = pure (c1, c2) }
+-- | set color of title message
+setOther :: Bool -> Color -> Color -> POptsL
+setOther b c1 c2 = mempty { oOther = pure $ coerce (b, c1, c2) }
 
+-- | turn on/off colors
 setNoColor :: Bool -> POptsL
 setNoColor b = mempty { oNoColor = pure b }
 
+-- | display type eg 'Unicode' or 'Ansi'
 setDisp :: Disp -> POptsL
 setDisp d = mempty { oDisp = pure d }
 
+-- | create color palette for the expression tree
 setCreateColor :: String
    -> Color
    -> Color
@@ -462,10 +482,12 @@        PresentP -> color c7 . bgColor c8
   in mempty { oColor = pure (s,PColor pc) }
 
+-- | set debug mode
 setDebug :: Debug -> POptsL
 setDebug d =
   mempty { oDebug = pure d }
 
+-- | monoid opts
 type POptsL = HOpts Last
 
 instance Monoid (HOpts Last) where
@@ -490,6 +512,7 @@           | Unicode  -- ^ use unicode
           deriving (Show, Eq)
 
+-- | default options
 defOpts :: POpts
 defOpts = HOpts
     { oWidth = 200
@@ -502,13 +525,15 @@     , oNoColor = False
     }
 
-otherDef :: (Color, Color)
-otherDef = (Magenta, Default)
+-- | default title message color and boundaries between multipart refine messages
+otherDef :: (Bool, SColor, SColor)
+otherDef = coerce (True, Default, Default)
 
 nocolor, colorDef :: (String, PColor)
 nocolor = ("nocolor", PColor $ flip const)
 colorDef = fromJust $ getLast $ oColor $ getOptT' @Color5
 
+-- | how much detail to show in the expression tree
 data Debug =
        DZero -- ^ one line summary used mainly for testing
      | DLite -- ^ one line summary with additional context from the head of the evaluation tree
@@ -521,14 +546,6 @@ isVerbose :: POpts -> Bool
 isVerbose = (DVerbose==) . oDebug
 
-markBoundary :: POpts -> String -> String
-markBoundary o =
-  if hasNoColor o then id else coerce (snd (oColor o)) PresentP
-
--- | color flag
-hasNoColor :: POpts -> Bool
-hasNoColor = oNoColor
-
 -- | color palettes
 type Color1 = 'OColor "color1" 'Default 'Blue 'Default 'Red 'Black 'Cyan 'Black 'Yellow
 type Color2 = 'OColor "color2" 'Default 'Magenta 'Default 'Red 'Black 'White 'Black 'Yellow
@@ -536,6 +553,9 @@ type Color4 = 'OColor "color4" 'Default 'Red 'Red 'Default 'Green 'Default 'Black 'Yellow
 type Color5 = 'OColor "color5" 'Blue 'Default 'Red 'Default 'Cyan 'Default 'Yellow 'Default
 
+type Other1 = 'OOther 'True 'Yellow 'Default
+type Other2 = 'OOther 'True 'Default 'Default
+
 -- | fix PresentT Bool to TrueT or FalseT
 fixBoolT :: TT Bool -> TT Bool
 fixBoolT t =
@@ -666,13 +686,15 @@ instance GetROpt 'Utf8 where getROpt = RL.utf8
 instance GetROpt 'No_utf8_check where getROpt = RL.no_utf8_check
 
+-- | simple regex string replacement options
 data ReplaceFnSub = RPrepend | ROverWrite | RAppend deriving (Show,Eq)
 
-class ReplaceFnSubC (k :: ReplaceFnSub) where
+-- | extract replacement options from typelevel
+class GetReplaceFnSub (k :: ReplaceFnSub) where
   getReplaceFnSub :: ReplaceFnSub
-instance ReplaceFnSubC 'RPrepend where getReplaceFnSub = RPrepend
-instance ReplaceFnSubC 'ROverWrite where getReplaceFnSub = ROverWrite
-instance ReplaceFnSubC 'RAppend where getReplaceFnSub = RAppend
+instance GetReplaceFnSub 'RPrepend where getReplaceFnSub = RPrepend
+instance GetReplaceFnSub 'ROverWrite where getReplaceFnSub = ROverWrite
+instance GetReplaceFnSub 'RAppend where getReplaceFnSub = RAppend
 
 -- | used by 'Predicate.ReplaceImpl' and 'RH.sub' and 'RH.gsub' to allow more flexible replacement
 --   These parallel the RegexReplacement (not exported) class in "Text.Regex.PCRE.Heavy" but have overlappable instances which is problematic for this code so I use 'RReplace'
@@ -689,7 +711,7 @@            RReplace2 {} -> "RReplace2 <fn>"
            RReplace3 {} -> "RReplace3 <fn>"
 
--- | extract values from the trees or if there are errors returned a tree with added context
+-- | extract values from the trees or if there are errors return a tree with context
 splitAndAlign :: Show x =>
                     POpts
                     -> String
@@ -704,6 +726,12 @@                        (map (hh . snd) ts)
      ([], tfs) -> Right tfs
 
+groupErrors :: [String] -> String
+groupErrors =
+     intercalate " | "
+   . map (\xs@(x :| _) -> x <> (if length xs > 1 then "(" <> show (length xs) <> ")" else ""))
+   . N.group
+
 partitionTTExtended :: (w, TT a) -> Either ((w, TT x), String) (a, w, TT a)
 partitionTTExtended (s, t) =
   case _tBool t of
@@ -732,28 +760,26 @@               FalseT -> Just False
               FailT {} -> Nothing
 
-groupErrors :: [String] -> String
-groupErrors =
-     intercalate " | "
-   . map (\xs@(x :| _) -> x <> (if length xs > 1 then "(" <> show (length xs) <> ")" else ""))
-   . N.group
-
+-- | 'FailT' prism
 _FailT :: Prism' (BoolT a) String
 _FailT = prism' FailT $ \case
                          FailT s -> Just s
                          _ -> Nothing
 
+-- | 'PresentT' prism
 _PresentT :: Prism' (BoolT a) a
 _PresentT = prism' PresentT $ \case
                                 PresentT a -> Just a
                                 _ -> Nothing
 
+-- | 'FalseT' prism
 _FalseT :: Prism' (BoolT Bool) ()
 _FalseT = prism' (const FalseT) $
             \case
                FalseT -> Just ()
                _ -> Nothing
 
+-- | 'TrueT' prism
 _TrueT :: Prism' (BoolT Bool) ()
 _TrueT = prism' (const TrueT) $
             \case
@@ -773,7 +799,7 @@ --
 -- >>> False ~> True
 -- True
-
+--
 (~>) :: Bool -> Bool -> Bool
 p ~> q = not p || q
 infixr 1 ~>
@@ -789,27 +815,27 @@              ':<>: 'GL.Text " and "
              ':<>: 'GL.ShowType n)
 
--- | helper method to fail with a msg when True
+-- | helper method that fails with a msg when True
 type family FailWhenT (b :: Bool) (msg :: GL.ErrorMessage) :: Constraint where
   FailWhenT 'False _ = ()
   FailWhenT 'True e = GL.TypeError e
 
--- | helper method to fail with msg when False
+-- | helper method that fails with msg when False
 type family FailUnlessT (b :: Bool) (msg :: GL.ErrorMessage) :: Constraint where
   FailUnlessT 'True _ = ()
   FailUnlessT 'False e = GL.TypeError e
 
--- | typelevel And
+-- | typelevel boolean And
 type family AndT (b :: Bool) (b1 :: Bool) :: Bool where
   AndT 'False _ = 'False
   AndT 'True b1 = b1
 
--- | typelevel Or
+-- | typelevel boolean Or
 type family OrT (b :: Bool) (b1 :: Bool) :: Bool where
   OrT 'True _ = 'True
   OrT 'False b1 = b1
 
--- | typelevel Not
+-- | typelevel boolean Not
 type family NotT (b :: Bool) :: Bool where
   NotT 'True = 'False
   NotT 'False = 'True
@@ -893,13 +919,14 @@ instance GetLen xs => GetLen (x ':| xs) where
   getLen = 1 + getLen @xs
 
-
+-- | display constructor name for 'These'
 showThese :: These a b -> String
 showThese = \case
   This {} -> "This"
   That {} -> "That"
   These {} -> "These"
 
+-- | get 'These' from typelevel
 class GetThese th where
   getThese :: (String, These w v -> Bool)
 instance GetThese ('This x) where
@@ -909,18 +936,6 @@ instance GetThese ('These x y) where
   getThese = ("These", isThese)
 
-isThis :: These a b -> Bool
-isThis This {} = True
-isThis _ = False
-
-isThat :: These a b -> Bool
-isThat That {} = True
-isThat _ = False
-
-isThese :: These a b -> Bool
-isThese These {} = True
-isThese _ = False
-
 -- | get ordering from the typelevel
 class GetOrdering (cmp :: Ordering) where
   getOrdering :: Ordering
@@ -931,7 +946,7 @@ instance GetOrdering 'GT where
   getOrdering = GT
 
--- | get Bool from the typelevel
+-- | get 'Bool' from the typelevel
 class GetBool (a :: Bool) where
   getBool :: Bool
 instance GetBool 'True where
@@ -939,7 +954,7 @@ instance GetBool 'False where
   getBool = False
 
--- | get Disp from the typelevel
+-- | get 'Disp' from the typelevel
 class GetDisp (a :: Disp) where
   getDisp :: Disp
 instance GetDisp 'Ansi where
@@ -947,7 +962,7 @@ instance GetDisp 'Unicode where
   getDisp = Unicode
 
--- | get Debug from the typelevel
+-- | get 'Debug' from the typelevel
 class GetDebug (a :: Debug) where
   getDebug :: Debug
 instance GetDebug 'DZero where
@@ -961,7 +976,7 @@ instance GetDebug 'DVerbose where
   getDebug = DVerbose
 
--- | get Color from the typelevel
+-- | get 'Color' from the typelevel
 class GetColor (a :: Color) where
   getColor :: Color
 instance GetColor 'Black where
@@ -983,8 +998,10 @@ instance GetColor 'Default where
   getColor = Default
 
+-- | all the ways to compare two values
 data OrderingP = CGt | CGe | CEq | CLe | CLt | CNe deriving (Show, Eq, Enum, Bounded)
 
+-- | extract 'OrderingP' from the typelevel
 class GetOrd (k :: OrderingP) where
   getOrd :: Ord a => (String, a -> a -> Bool)
 
@@ -995,9 +1012,11 @@ instance GetOrd 'CLt where getOrd = ("<", (<))
 instance GetOrd 'CNe where getOrd = ("/=",(/=))
 
+-- | pretty print a tree
 toNodeString :: POpts -> PE -> String
 toNodeString opts bpe =
-  if hasNoTree opts then errorInProgram $ "shouldnt be calling this if we are dropping details: toNodeString " <> show (oDebug opts) <> " " <> show bpe
+  if hasNoTree opts
+  then errorInProgram $ "shouldnt be calling this if we are dropping details: toNodeString " <> show (oDebug opts) <> " " <> show bpe
   else colorBoolP opts (_pBool bpe) <> " " <> _pString bpe
 
 hasNoTree :: POpts -> Bool
@@ -1013,6 +1032,7 @@ nullSpace s | null s = ""
             | otherwise = " " <> s
 
+-- | render the 'BoolP' value with colors
 colorBoolP :: POpts -> BoolP -> String
 colorBoolP o =
   \case
@@ -1021,8 +1041,9 @@     b@TrueP -> colorMe o b "True"
     b@FalseP -> colorMe o b "False"
 
-colorBoolT' :: Show a => POpts -> BoolT a -> String
-colorBoolT' o r =
+-- | render the 'BoolT' value with colors
+colorBoolT :: Show a => POpts -> BoolT a -> String
+colorBoolT o r =
   let f = colorMe o (r ^. boolT2P)
   in case r of
       FailT e -> f "Error" <> " " <> e
@@ -1030,8 +1051,8 @@       FalseT -> f "False"
       PresentT x -> f "Present" <> " " <> show x
 
-colorBoolT :: Show a => POpts -> BoolT a -> String
-colorBoolT o r =
+colorBoolT' :: Show a => POpts -> BoolT a -> String
+colorBoolT' o r =
   let f = colorMe o (r ^. boolT2P)
   in case r of
       FailT e -> f "FailT" <> " " <> e
@@ -1042,21 +1063,9 @@ -- | colors the result of the predicate based on the current color palette
 colorMe :: POpts -> BoolP -> String -> String
 colorMe o b s =
-  let (_, PColor f) = oColor o
+  let (_, PColor f) = if oNoColor o then nocolor else oColor o
   in f b s
 
-prtTTIO :: POpts -> IO (TT a) -> IO ()
-prtTTIO  = prtTT'
-
-prtTT :: POpts -> Identity (TT a) -> IO ()
-prtTT  = prtTT'
-
-prtTT' :: MonadEval m => POpts -> m (TT a) -> IO ()
-prtTT' o y = liftEval y >>= prtTree o . fromTT
-
-prtTree :: POpts -> Tree PE -> IO ()
-prtTree o = putStr . prtTreePure o
-
 fixLite :: forall a . Show a => POpts -> a -> Tree PE -> String
 fixLite opts a t
   | hasNoTree opts = fixPresentP opts (t ^. root . pBool) a <> "\n"
@@ -1328,6 +1337,7 @@   | OMsg !Symbol      -- ^ set text to add context to a failure message for refined types
   | ORecursion !Nat       -- ^ set recursion limit eg for regex
   | OOther                -- ^ set effects for messages
+     !Bool    -- ^ set underline
      !Color   -- ^ set foreground color
      !Color   -- ^ set background color
   | OEmpty                -- ^ mempty
@@ -1358,7 +1368,7 @@             OWidth _n -> "OWidth"
             OMsg _s -> "OMsg"
             ORecursion _n -> "ORecursion"
-            OOther _c1 _c2 -> "OOther"
+            OOther _b _c1 _c2 -> "OOther"
             OEmpty -> "OEmpty"
             a :# b -> show a ++ " ':# " ++ show b
             OColor _s _c1 _c2 _c3 _c4 _c5 _c6 _c7 _c8 -> "OColor"
@@ -1373,15 +1383,7 @@             OUB -> "OUB"
 
 infixr 6 :#
-{- type families/synonyms expand
-type OZ = 'ODisp 'Ansi ':# 'ONoColor 'True ':# 'ODebug 'DZero
-type OL = 'ODisp 'Ansi ':# 'ONoColor 'True ':# 'ODebug 'DLite
-type OAN = 'ODisp 'Ansi ':# 'ONoColor 'True
-type OA = 'ODisp 'Ansi ':# Color5
-type OAB = 'ODisp 'Ansi ':# Color1
-type OU = 'ODisp 'Unicode ':# Color5
-type OUB = 'ODisp 'Unicode ':# Color1
--}
+
 class OptTC (k :: OptT) where
    getOptT' :: POptsL
 instance GetDebug n => OptTC ('ODebug n) where
@@ -1392,8 +1394,8 @@    getOptT' = setMessage (symb @s)
 instance KnownNat n => OptTC ('ORecursion n) where
    getOptT' = setRecursion (nat @n)
-instance (GetColor c1, GetColor c2) => OptTC ('OOther c1 c2) where
-   getOptT' = setOther (getColor @c1) (getColor @c2)
+instance (GetBool b, GetColor c1, GetColor c2) => OptTC ('OOther b c1 c2) where
+   getOptT' = setOther (getBool @b) (getColor @c1) (getColor @c2)
 instance OptTC 'OEmpty where
    getOptT' = mempty
 instance (OptTC a, OptTC b) => OptTC (a ':# b) where
@@ -1429,13 +1431,13 @@ instance OptTC 'OAN where
    getOptT' = setDisp Ansi <> setNoColor True <> setDebug DNormal
 instance OptTC 'OA where
-   getOptT' = setDisp Ansi <> getOptT' @Color5 <> setDebug DNormal
+   getOptT' = setDisp Ansi <> getOptT' @Color5 <> setDebug DNormal <> getOptT' @Other2
 instance OptTC 'OAB where
-   getOptT' = setDisp Ansi <> getOptT' @Color1 <> setDebug DNormal
+   getOptT' = setDisp Ansi <> getOptT' @Color1 <> setDebug DNormal <> getOptT' @Other1
 instance OptTC 'OU where
-   getOptT' = setDisp Unicode <> getOptT' @Color5 <> setDebug DNormal
+   getOptT' = setDisp Unicode <> getOptT' @Color5 <> setDebug DNormal <> getOptT' @Other2
 instance OptTC 'OUB where
-   getOptT' = setDisp Unicode <> getOptT' @Color1 <> setDebug DNormal
+   getOptT' = setDisp Unicode <> getOptT' @Color1 <> setDebug DNormal <> getOptT' @Other1
 
 -- | convert typelevel options to 'POpts'
 --
@@ -1445,6 +1447,15 @@ -- >>> oMsg (getOptT @('OMsg "abc" ':# 'OMsg "def"))
 -- ["abc","def"]
 --
+-- >>> oOther (getOptT @('OOther 'False 'Red 'White ':# 'OOther 'True 'Red 'Black))
+-- (True,Red,Black)
+--
+-- >>> a = show (getOptT @('OEmpty ':# 'OU))
+-- >>> b = show (getOptT @('OU ':# 'OEmpty));
+-- >>> c = show (getOptT @'OU)
+-- >>> a==b && b==c
+-- True
+--
 getOptT :: forall o . OptTC o => POpts
 getOptT = reifyOpts (getOptT' @o)
 
@@ -1479,7 +1490,7 @@ formatOMsg o suffix =
   case oMsg o of
     [] -> mempty
-    s@(_:_) -> setOtherEffects o (intercalate " | " s) <> suffix
+    s@(_:_) -> intercalate " | " (map (setOtherEffects o) s) <> suffix
 
 subopts :: POpts -> POpts
 subopts opts =
@@ -1490,8 +1501,23 @@ setOtherEffects :: POpts -> String -> String
 setOtherEffects o =
   if oNoColor o then id
-  else case oOther o of
-         (Default, Default) -> id
-         (c1,c2) -> color c1 . bgColor c2
+  else case coerce (oOther o) of
+         (False, Default, Default) -> id
+         (b, c1, c2) -> (if b then style Underline else id) . color c1 . bgColor c2
 
-type family AnyT :: k where {}+type family AnyT :: k where {}
+
+pureTryTest :: a -> IO (Either () a)
+pureTryTest = fmap (left (const ())) . E.try @E.SomeException . E.evaluate
+
+pureTryTestPred :: (String -> Bool) -> a -> IO (Either String (Either () a))
+pureTryTestPred p a = do
+  lr <- left E.displayException <$> E.try @E.SomeException (E.evaluate a)
+  return $ case lr of
+    Left e | p e -> Right (Left ())
+           | otherwise -> Left ("no match found: e=" ++ e)
+    Right r -> Right (Right r)
+
+isPrime :: Int -> Bool
+isPrime n = n==2 || n>2 && all ((> 0).rem n) (2:[3,5 .. floor . sqrt @Double . fromIntegral $ n+1])
+
test/TestRefined.hs view
@@ -12,11 +12,7 @@ {-# LANGUAGE ScopedTypeVariables #-}
 {-# LANGUAGE OverloadedStrings #-}
 {-# LANGUAGE NoOverloadedLists #-} -- overloaded lists breaks some predicates
-{-# LANGUAGE ViewPatterns #-}
 {-# LANGUAGE FlexibleContexts #-}
-{-# LANGUAGE DeriveGeneric #-}
-{-# LANGUAGE TemplateHaskell #-}
-{-# LANGUAGE LambdaCase #-}
 {-# LANGUAGE NoStarIsType #-}
 module TestRefined where
 import TastyExtras
test/TestRefined2.hs view
@@ -11,10 +11,8 @@ {-# LANGUAGE ScopedTypeVariables #-}
 {-# LANGUAGE OverloadedStrings #-}
 {-# LANGUAGE NoOverloadedLists #-} -- overloaded lists breaks some predicates
-{-# LANGUAGE ViewPatterns #-}
 {-# LANGUAGE FlexibleContexts #-}
 {-# LANGUAGE DeriveGeneric #-}
-{-# LANGUAGE TemplateHaskell #-}
 {-# LANGUAGE LambdaCase #-}
 {-# LANGUAGE NoStarIsType #-}
 module TestRefined2 where
test/TestRefined3.hs view
@@ -11,10 +11,8 @@ {-# LANGUAGE ScopedTypeVariables #-}
 {-# LANGUAGE OverloadedStrings #-}
 {-# LANGUAGE NoOverloadedLists #-} -- overloaded lists breaks some predicates
-{-# LANGUAGE ViewPatterns #-}
 {-# LANGUAGE FlexibleContexts #-}
 {-# LANGUAGE DeriveGeneric #-}
-{-# LANGUAGE TemplateHaskell #-}
 {-# LANGUAGE LambdaCase #-}
 {-# LANGUAGE NoStarIsType #-}
 module TestRefined3 where