predicate-transformers 0.8.0.0 → 0.9.0.0
raw patch · 3 files changed
+101/−69 lines, 3 filesdep ~adjunctionsdep ~basedep ~deepseqPVP ok
version bump matches the API change (PVP)
Dependency ranges changed: adjunctions, base, deepseq, lens, mtl, semigroups
API changes (from Hackage documentation)
- PredicateTransformers: (==>) :: a -> b -> (a, b)
+ PredicateTransformers: instance PredicateTransformers.Predicatory a => PredicateTransformers.Predicatory (e -> a)
+ PredicateTransformers: pattern (:=>) :: a -> b -> (a, b)
+ PredicateTransformers: traceFailFun :: (Predicatory p, Exceptional p) => (e -> a -> String) -> PT (e -> p) a a
Files
- CHANGELOG.md +10/−0
- predicate-transformers.cabal +8/−8
- src/PredicateTransformers.hs +83/−61
CHANGELOG.md view
@@ -1,5 +1,15 @@ # Revision history for predicate-transformers +## 0.9.0.0 -- 2024-07-21++* Add instance Predicatory (e -> a). This will allow for adding extra+ parameters to predicates, making it easier to compose them; maybe+ these are called "functional predicates".+* Added traceFailFun. This version of traceFail works on functional+ predicates.+* Tupling sugar renamed from ==> to :=>, to allow i to be a pattern synonym.+* Minor code style changes.+ ## 0.1.0.0 -- 2019-10-05 * First version. Released on an unsuspecting world.
predicate-transformers.cabal view
@@ -1,7 +1,7 @@ cabal-version: 2.4 name: predicate-transformers-version: 0.8.0.0+version: 0.9.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.@@ -10,7 +10,7 @@ author: Edmund Noble maintainer: edmundnoble@gmail.com category: Data-extra-source-files: CHANGELOG.md+extra-doc-files: CHANGELOG.md source-repository head type: git location: https://gitlab.com/edmundnoble/predicate-transformers@@ -18,13 +18,13 @@ library exposed-modules: PredicateTransformers build-depends:- base >=4.8 && <4.21- ,lens >=4.17- ,adjunctions >=4.2- ,mtl >=2.2- ,deepseq >=1.3+ base >=4.8 && <4.30+ ,adjunctions >= 4.4.2 && < 5+ ,deepseq >= 1.4.8 && < 2+ ,mtl >= 2.3.1 && < 3+ ,lens >= 5.3.2 && < 6 if !impl(ghc >= 8.0) build-depends:- semigroups >= 0.8.4+ semigroups >= 0.8.4 && < 1 hs-source-dirs: src default-language: Haskell2010
src/PredicateTransformers.hs view
@@ -1,7 +1,8 @@-{-# language ViewPatterns #-}-{-# language LambdaCase #-}-{-# language RankNTypes #-}-{-# language FlexibleInstances #-}+{-# LANGUAGE FlexibleInstances #-}+{-# LANGUAGE LambdaCase #-}+{-# LANGUAGE RankNTypes #-}+{-# LANGUAGE ViewPatterns #-}+{-# LANGUAGE PatternSynonyms #-} -- | 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@.@@ -13,19 +14,18 @@ -- `Data.Foldable.all`, `Data.Foldable.any` (base) -- `either` (base) -- `Control.Lens.allOf` (lens)- module PredicateTransformers where import Control.Applicative-import Control.DeepSeq(NFData, force)-import Control.Exception(SomeException, Exception, evaluate, throwIO, try)+import Control.DeepSeq (NFData, force)+import Control.Exception (Exception, SomeException, evaluate, throwIO, try) import Control.Lens hiding (index, zoom) import Control.Monad-import Control.Monad.Writer(execWriter, tell)+import Control.Monad.Writer (execWriter, tell) import Data.Bool-import Data.Foldable(toList)-import Data.Functor.Rep(Representable(..))-import Data.Semigroup(All(..), Any(..))+import Data.Foldable (toList)+import Data.Functor.Rep (Representable (..))+import Data.Semigroup (All (..), Any (..)) import Data.Typeable import Debug.Trace import System.IO.Unsafe@@ -36,6 +36,12 @@ stop :: a continue :: a +instance Predicatory a => Predicatory (e -> a) where+ (f `oneOfTwo` f') e = f e `oneOfTwo` f' e+ (f `also` f') e = f e `also` f' e+ stop = \_ -> stop+ continue = \_ -> continue+ class Exceptional a where assess :: a -> IO () @@ -64,107 +70,111 @@ instance Exceptional (IO ()) where assess x = x >>= evaluate --- |A convenient alias for predicates.+-- | A convenient alias for predicates. type Pred a = a -> Bool --- |Predicate transformers form a category where composition is ordinary function composition.--- Forms a category with `.` and `id`.--- Multiple are already provided by the standard library,--- for instance `Data.Foldable.all` and `Data.Foldable.any`.+-- | Predicate transformers form a category where composition is ordinary function composition.+-- Forms a category with `.` and `id`.+-- Multiple are already provided by the standard library,+-- for instance `Data.Foldable.all` and `Data.Foldable.any`. type PT p a b = (a -> p) -> (b -> p) --- |Operate on the target of a prism, or fail.+-- | Operate on the target of a prism, or fail. match :: Predicatory p => APrism s t a b -> PT p a s match p pred = either (const stop) pred . matching p --- |Operate on the `Just` branch of a `Maybe`, or fail.+-- | Operate on the `Just` branch of a `Maybe`, or fail. just :: Predicatory p => PT p a (Maybe a) just = match _Just --- |Operate on the `Left` branch of an `Either`, or fail.+-- | Operate on the `Left` branch of an `Either`, or fail. left :: Predicatory p => PT p e (Either e a) left = match _Left --- |Operate on the `Right` branch of an `Either`, or fail.+-- | Operate on the `Right` branch of an `Either`, or fail. right :: Predicatory p => PT p a (Either e a) right = match _Right --- |Operate on the last value in a foldable, or fail if it's not present.+-- | Operate on the last value in a foldable, or fail if it's not present. endingWith :: (Predicatory p, Foldable f) => PT p a (f a) endingWith _ (toList -> []) = stop endingWith p (toList -> xs) = p $ last xs-{-# inlinable endingWith #-}+{-# INLINEABLE endingWith #-} --- |Operate on the first value in a foldable, or fail if it's not present.+-- | 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 p (toList -> (x : _)) = p x startingWith _ (toList -> []) = stop-{-# inlinable startingWith #-}+{-# INLINEABLE startingWith #-} --- |Require that a foldable has a single element, and operate on that element.+-- | Require that a foldable has a single element, and operate on that element. only :: (Predicatory p, Foldable f) => PT p a (f a) only p (toList -> [x]) = p x only _ _ = stop-{-# inlinable only #-}+{-# INLINEABLE only #-} --- |Only test the @k@th element of a foldable.+-- | 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-{-# inlinable kth #-}+{-# 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.+-- | 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. list :: Predicatory p => [a -> p] -> [a] -> p-list (p:ps) (x:xs) = p x `also` list ps xs+list (p : ps) (x : xs) = p x `also` list ps xs list [] [] = continue list _ _ = stop --- |Given a functor-full of predicates, and a functor-full of values, ensure that the structures--- of the two functors match and apply all of the predicates to all of the values.--- Generalized version of `list`.+-- | Given a functor-full of predicates, and a functor-full of values, ensure that the structures+-- of the two functors match and apply all of the predicates to all of the values.+-- Generalized version of `list`. dist ::- (Predicatory p, Eq (f ()), Functor f, Foldable f) =>- f (a -> p) -> f a -> p+ (Predicatory p, Eq (f ()), Functor f, Foldable f) =>+ f (a -> p) ->+ f a ->+ p dist preds values =- bool stop continue ((() <$ preds) == (() <$ values)) `also`- list (toList preds) (toList values)-{-# inlinable dist #-}+ 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`.-distRep :: Representable f =>- f (a -> p) -> f a -> f p+-- | Given a representable functor-full of predicates, and a functor-full of values,+-- yield a representable functor-full of booleans. Similar to `dist`.+distRep ::+ Representable f =>+ f (a -> p) ->+ f a ->+ f p distRep pr fa = tabulate (\r -> index pr r $ index fa r)-{-# inlinable distRep #-}+{-# INLINEABLE distRep #-} --- |Test all predicates against one value.+-- | Test all predicates against one value. allTrue :: (Predicatory p, Foldable f) => f (a -> p) -> a -> p-allTrue ps a = foldr (\p r -> p a `also` r) continue $ ps+allTrue ps a = foldr (\p r -> p a `also` r) continue ps --- |Check that a predicate is true for all values behind a generalized getter--- and that there's at least one value for which it's true.+-- | Check that a predicate is true for all values behind a generalized getter+-- and that there's at least one value for which it's true. allOf1 :: Predicatory p => Fold s a -> PT p a s allOf1 g p vs =- bool stop continue (notNullOf g vs) `also`- foldrOf g (\x r -> p x `also` r) continue vs+ bool stop continue (notNullOf g vs)+ `also` foldrOf g (\x r -> p x `also` r) continue vs --- |Sugar for tupling.-(==>) :: a -> b -> (a, b)-(==>) = (,)+-- | Sugar for tupling.+pattern a :=> b = (a, b) pair :: Predicatory p => (a -> p) -> (b -> p) -> (a, b) -> p pair f s (a, b) = f a `also` s b --- |Flipped function composition; @f !@ for a function @f@ is a predicate transformer.+-- | Flipped function composition; @f !@ for a function @f@ is a predicate transformer. (!) :: (b -> a) -> (a -> c) -> b -> c (!) = flip (.) --- |Prints the input of a predicate, for debugging.+-- | Prints the input of a predicate, for debugging. traced :: Show a => (a -> c) -> a -> c traced p a = traceShow 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.+-- | 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@@ -176,12 +186,24 @@ 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 --- |Predicate which always succeeds.++-- | Predicate which always succeeds. something :: Predicatory p => a -> p something = const continue --- |Predicate which triggers full evaluation of its input and succeeds.--- Useful for testing that an exception isn't thrown.+-- | Predicate which triggers full evaluation of its input and succeeds.+-- Useful for testing that an exception isn't thrown. forced :: (Predicatory p, NFData a) => a -> p forced a = force a `seq` continue