packages feed

predicate-transformers 0.10.0.0 → 0.11.0.0

raw patch · 3 files changed

+57/−40 lines, 3 filesPVP ok

version bump matches the API change (PVP)

API changes (from Hackage documentation)

- PredicateTransformers: onlyContains :: (Predicatory p, Foldable f) => PT p a (f a)
- PredicateTransformers: traceFailFun :: (Predicatory p, Exceptional p) => (e -> a -> String) -> PT (e -> p) a a
+ PredicateTransformers: instance PredicateTransformers.Exceptional a => PredicateTransformers.Exceptional (e -> a)
+ PredicateTransformers: sole :: (Predicatory p, Foldable f) => PT p a (f a)
+ PredicateTransformers: soleOf :: Predicatory p => Fold s a -> PT p a s
+ PredicateTransformers: tracedShow :: Show a => PT c a a
- PredicateTransformers: assess :: Exceptional a => a -> IO ()
+ PredicateTransformers: assess :: Exceptional a => a -> IO () -> a
- PredicateTransformers: traced :: Show a => (a -> c) -> a -> c
+ PredicateTransformers: traced :: Show a => (a -> String) -> PT c a a

Files

CHANGELOG.md view
@@ -1,5 +1,13 @@ # Revision history for predicate-transformers +## 0.11.0.0 -- 2024-07-21+* Add documentation.+* Rename `onlyContains` to `sole`. Add `soleOf`, generalizing over `Fold`s.+  `soleOf` is likely a better replacement for `match` than `allOf1` was.+* Exchange `INLINABLE` pragmas for `-fexpose-all-unfoldings`.+* Implement `traceFailFunShow`.+* Change `Exceptional`'s method `assess` to make it possible to implement for functional predicates, and delete `traceFailFun`, now redundant.+ ## 0.10.0.0 -- 2024-07-21  * Rename `oneOfTwo` to `otherHand`, for easier reading.
predicate-transformers.cabal view
@@ -1,7 +1,7 @@ cabal-version: 2.4  name: predicate-transformers-version: 0.10.0.0+version: 0.11.0.0 synopsis: A library for writing predicates and transformations over predicates in Haskell description:   This package provides ways to write predicates such that they compose nicely and are easy to debug.
src/PredicateTransformers.hs view
@@ -4,6 +4,7 @@ {-# LANGUAGE ViewPatterns #-} {-# LANGUAGE PatternSynonyms #-} {-# LANGUAGE ScopedTypeVariables #-}+{-# OPTIONS_GHC -fexpose-all-unfoldings #-}  -- | This library is based on the notion of a predicate transformer, the below -- type @PT a b@, which is a function from @a@ to predicates on @b@.@@ -32,12 +33,19 @@ import System.IO.Unsafe import Control.Concurrent (myThreadId, throwTo) import Control.Exception (SomeAsyncException)+import GHC.Conc (pseq) +-- | Class of possible predicate results.+-- This is mostly a lattice with `otherHand` as disjunction, `also` as conjunction, `stop` as the falsy+-- value, and `continue` as the truthy value. There may be multiple falsy values, however.+-- Note that test failure messages are not really the domain of this library.+-- It's the author's hope that they can be mostly replaced by `traceFail`. class Predicatory a where   otherHand :: a -> a -> a   also :: a -> a -> a   stop :: a   continue :: a+  {-# MINIMAL otherHand, also, stop, continue #-}  instance Predicatory a => Predicatory (e -> a) where   (f `otherHand` f') e = f e `otherHand` f' e@@ -48,10 +56,14 @@ infixr 3 `also` infixr 2 `otherHand` --- | Class of predicate results which can be checked for failure, by surfacing an exception.+-- | Class of predicate results which can be checked for failure,+--   by triggering an action. class Exceptional a where-  assess :: a -> IO ()+  assess :: a -> IO () -> a +instance Exceptional a => Exceptional (e -> a) where+  assess f act = \e -> assess (f e) act+ -- | The exception thrown by predicates of type `IO ()` by default. Other IOExceptions will work fine. data PredicateFailed = PredicateFailed   deriving (Show, Typeable)@@ -65,9 +77,9 @@   continue = True  instance Exceptional Bool where-  assess b = do-    evaluate b-    unless b stop+  assess b act+    | b = b+    | otherwise = unsafePerformIO act `pseq` b  instance Predicatory (IO ()) where   otherHand x y = do@@ -84,7 +96,16 @@   continue = return ()  instance Exceptional (IO ()) where-  assess x = x >>= evaluate+  assess x act =+    catches x+      -- explicitly do not handle async exceptions.+      -- otherwise, a thread being killed may appear as a predicate failure.+      [ Handler $ \(ex :: SomeAsyncException) -> do+        tid <- myThreadId+        throwTo tid ex+      , Handler $ \(ex :: SomeException) ->+        act >> throwIO ex+      ]  -- | A convenient alias for predicates. type Pred a = a -> Bool@@ -111,24 +132,24 @@ endingWith :: (Predicatory p, Foldable f) => PT p a (f a) endingWith _ (toList -> []) = stop endingWith p (toList -> xs) = p $ last xs-{-# INLINEABLE endingWith #-}  -- | Operate on the first value in a foldable, or fail if it's not present. startingWith :: (Predicatory p, Foldable f) => PT p a (f a) startingWith p (toList -> (x : _)) = p x startingWith _ (toList -> []) = stop-{-# INLINEABLE startingWith #-} --- | Require that a foldable has a single element, and operate on that element.-onlyContains :: (Predicatory p, Foldable f) => PT p a (f a)-onlyContains p (toList -> [x]) = p x-onlyContains _ _ = stop-{-# INLINEABLE onlyContains #-}+-- | Require that a @Fold@ has a single element, and operate on that element.+soleOf :: (Predicatory p) => Fold s a -> PT p a s+soleOf f p (toListOf f -> [x]) = p x+soleOf _ _ _ = stop +-- | Require that a @Foldable@ has a single element, and operate on that element.+sole :: (Predicatory p, Foldable f) => PT p a (f a)+sole = soleOf folded+ -- | Only test the @k@th element of a foldable. kth :: (Predicatory p, Foldable f) => Int -> PT p a (f a) kth k p = startingWith p . drop k . toList-{-# INLINEABLE kth #-}  -- | Given a list of predicates and a list of values, ensure that each predicate holds for each respective value. --  Fails if the two lists have different lengths.@@ -148,7 +169,6 @@ dist preds values =   bool stop continue ((() <$ preds) == (() <$ values))     `also` list (toList preds) (toList values)-{-# INLINEABLE dist #-}  -- | Given a representable functor-full of predicates, and a functor-full of values, --  yield a representable functor-full of booleans. Similar to `dist`.@@ -158,7 +178,6 @@   f a ->   f p distRep pr fa = tabulate (\r -> index pr r $ index fa r)-{-# INLINEABLE distRep #-}  -- | Test all predicates against one value. allTrue :: (Predicatory p, Foldable f) => f (a -> p) -> a -> p@@ -174,6 +193,7 @@ -- | Sugar for tupling. pattern a :=> b = (a, b) +-- | A pair of predicates, made into a predicate on pairs. pair :: Predicatory p => (a -> p) -> (b -> p) -> (a, b) -> p pair f s (a, b) = f a `also` s b @@ -183,34 +203,23 @@ infixr 9 !  -- | Prints the input of a predicate, for debugging.-traced :: Show a => (a -> c) -> a -> c-traced p a = traceShow a (p a)+traced :: Show a => (a -> String) -> PT c a a+traced s p a = trace (s a) (p a) --- | Prints the input of a predicate, if the predicate fails.---   Requires that the predicate's output type includes a notion of failure.-traceFail :: (Predicatory p, Exceptional p) => (a -> String) -> PT p a a-traceFail s p a = unsafePerformIO $ do-  try (assess (p a)) >>= \case-    Left ex -> do-      traceIO (s a)-      throwIO (ex :: SomeException)-    Right () ->-      pure continue+-- | Prints the input of a predicate, for debugging.+tracedShow :: Show a => PT c a a+tracedShow = traced show +-- | Prints the input of a predicate, if the predicate fails, using `Show`.+--   Requires that the predicate's output type can be checked for failure. traceFailShow :: (Exceptional p, Predicatory p, Show a) => PT p a a traceFailShow = traceFail show------ | Prints the input of a predicate over functions, if the predicate fails.---   Requires that the predicate's output type includes a notion of failure.-traceFailFun :: (Predicatory p, Exceptional p) => (e -> a -> String) -> PT (e -> p) a a-traceFailFun s p a e = unsafePerformIO $ do-  try (assess (p a e)) >>= \case-    Left ex -> do-      traceIO (s e a)-      throwIO (ex :: SomeException)-    Right () ->-      pure continue +-- | Prints the input of a predicate over functions, if the predicate fails.+--   Requires that the predicate's output type can be checked for failure.+traceFail :: (Predicatory p, Exceptional p) => (a -> String) -> PT p a a+traceFail s p a =+  assess (p a) $ traceIO (s a)  -- | Predicate which always succeeds. something :: Predicatory p => a -> p