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 +8/−0
- predicate-transformers.cabal +1/−1
- src/PredicateTransformers.hs +48/−39
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