packages feed

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 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