packages feed

weighted 0.3.0.0 → 0.3.0.1

raw patch · 4 files changed

+147/−43 lines, 4 filesPVP: major bump suggested

API removals or changes: PVP suggests a major version bump

API changes (from Hackage documentation)

- Control.Monad.Weighted.Class: (#.) :: Coercible b c => (b -> c) -> (a -> b) -> a -> c
- Control.Monad.Weighted.Class: infixr 9 #.
- Control.Monad.Weighted.Class: toCont :: (Foldable m, MonadWeighted w m) => (a -> w) -> m a -> w
- Control.Monad.Weighted.Filter: catchZero :: (DetectableZero s, Alternative m) => (s -> m a) -> s -> m a
+ Control.Monad.Weighted.Class: toCovector :: (Foldable m, MonadWeighted w m) => m a -> (a -> w) -> w

Files

src/Control/Monad/Weighted.hs view
@@ -2,73 +2,139 @@ {-# LANGUAGE GeneralizedNewtypeDeriving #-} {-# LANGUAGE MultiParamTypeClasses      #-} {-# LANGUAGE PatternSynonyms            #-}+{-# LANGUAGE Strict                     #-} {-# LANGUAGE UndecidableInstances       #-} {-# LANGUAGE ViewPatterns               #-} +-- | This module provides monad transformer similar to+-- 'Control.Monad.Writer.Strict.WriterT', implemented using 'StateT', making it+-- tail recursive. (The traditional writer always leaks space: see+-- <https://mail.haskell.org/pipermail/libraries/2013-March/019528.html here>+-- for more information).+--+-- <https://downloads.haskell.org/~ghc/latest/docs/html/users_guide/glasgow_exts.html#pattern-synonyms Pattern Synonyms>+-- are used to provide the same interface as+-- 'Control.Monad.Writer.Strict.WriterT'. Unfortunately, current GHC warns+-- whenever these patterns are used that there are unmatched patterns: the+-- <https://ghc.haskell.org/trac/ghc/ticket/8779 COMPLETE> pragma should solve+-- this problem in future version of GHC.+--+-- A pattern synonym is also provided for a non-transformer version of writer.+-- Again, this is just 'StateT' underneath, but its interface looks as if it was+-- defined like so:+--+-- > newtype Writer w a = Writer { runWriter :: (a, w) }+--+-- The other difference between this monad and+-- 'Control.Monad.Writer.Strict.WriterT' is that it relies on '<.>' from+-- 'Semiring', rather than 'mappend' from 'Monoid'. module Control.Monad.Weighted-  (WeightedT+  (+   -- * Transformer+   WeightedT   ,runWeightedT   ,pattern WeightedT-  ,Weighted-  ,runWeighted-  ,pattern Weighted   ,execWeightedT   ,evalWeightedT+  ,+   -- * Plain+   Weighted+  ,runWeighted+  ,pattern Weighted   ,execWeighted   ,evalWeighted)   where - import           Control.Applicative-import           Control.Monad.Identity-import           Control.Monad.State.Strict -import           Control.Monad.Cont.Class-import           Control.Monad.Error.Class import           Control.Monad.Fail+import           Control.Monad.Identity+ import           Control.Monad.Reader.Class+import           Control.Monad.Weighted.Class import           Control.Monad.Writer.Class+import           Control.Monad.Cont.Class+import           Control.Monad.Error.Class -import           Control.Monad.Weighted.Class+import           Control.Monad.State.Strict  import           Data.Coerce+ import           Data.Functor.Classes  import           Data.Monoid import           Data.Semiring --- | A monad transformer similar to 'WriterT', except that it does not leak--- space, and it uses the 'Semiring' class, rather than 'Monoid'.+-- | A monad transformer similar to 'Control.Monad.Writer.Strict.WriterT', except+-- that it does not leak space. It is implemented using a state monad, so that+-- `mappend` is tail recursive. See+-- <https://mail.haskell.org/pipermail/libraries/2013-March/019528.html this>+-- email to the Haskell libraries committee for more information.+--+-- It also uses '<.>' from 'Semiring', rather than 'mappend' from 'Monoid' when+-- combining computations.+--+-- Wherever possible, coercions are used to eliminate any overhead from the+-- newtype wrapper. newtype WeightedT s m a =     WeightedT_ (StateT s m a)-    deriving (Functor,Applicative,Monad,MonadTrans,MonadCont,MonadError e-             ,MonadReader r,MonadFix,MonadFail,MonadIO,Alternative,MonadPlus-             ,MonadWriter w)+    deriving (Functor,Applicative,Monad,MonadTrans,MonadCont+             ,MonadError e,MonadReader r,MonadFix,MonadFail+             ,MonadIO,Alternative,MonadPlus,MonadWriter w) +-- | Run a weighted computation in the underlying monad. runWeightedT     :: Semiring s     => WeightedT s m a -> m (a, s) runWeightedT =     (coerce :: (StateT s m a -> m (a, s)) -> WeightedT s m a -> m (a, s))         (`runStateT` one)+ {-# INLINE runWeightedT #-} +{-# ANN module "HLint: ignore Use second" #-} +-- | This pattern gives the newtype wrapper around 'StateT' the same interface+-- as 'Control.Monad.Writer.Strict.WriterT'. Unfortunately, GHC currently warns+-- that a function is incomplete wherever this pattern is used. This issue+-- should be solved in a future version of GHC, when the+-- <https://ghc.haskell.org/trac/ghc/ticket/8779 COMPLETE> pragma is+-- implemented. pattern WeightedT :: (Functor m, Semiring s) =>         m (a, s) -> WeightedT s m a  pattern WeightedT x <- (runWeightedT -> x)   where WeightedT y-          = WeightedT_ (StateT (\ s -> (fmap . fmap) (s<.>) y))+          = WeightedT_ (StateT (\ s -> fmap (\ (x, p) -> (x, s <.> p)) y)) +-- | A type synonym for the plain (non-transformer) version of 'Weighted'. This+-- can be used as if it were defined as:+--+-- > newtype Weighted w a = Weighted { runWeighted :: (a, w) } type Weighted s = WeightedT s Identity +-- | This pattern gives the newtype wrapper around 'StateT' the same interface+-- as as if it was defined like so:+--+-- > newtype Weighted w a = Weighted { runWeighted :: (a, w) }+--+-- Unfortunately GHC warns that a function is incomplete wherever this pattern+-- is used. This issue should be solved in a future version of GHC, when the+-- <https://ghc.haskell.org/trac/ghc/ticket/8779 COMPLETE> pragma is+-- implemented.+--+-- >>> execWeighted $ traverse (\x -> Weighted ((), x)) [1..5]+-- 120 pattern Weighted :: Semiring s => (a, s) -> Weighted s a  pattern Weighted x <- (runWeighted -> x)   where Weighted (y, p)           = WeightedT_ (StateT (\ s -> Identity (y, (<.>) p s))) +-- | Run a weighted computation.+--+-- >>> runWeighted $ traverse (\x -> Weighted (show x, x)) [1..5]+-- (["1","2","3","4","5"],120) runWeighted     :: Semiring s     => Weighted s a -> (a, s)@@ -84,6 +150,7 @@     put = lift . put     state = lift . state +-- | Run a weighted computation in the underlying monad, and return its result. evalWeightedT     :: (Monad m, Semiring s)     => WeightedT s m a -> m a@@ -93,6 +160,7 @@  {-# INLINE evalWeightedT #-} +-- | Run a weighted computation in the underlying monad, and collect its weight. execWeightedT     :: (Monad m, Semiring s)     => WeightedT s m a -> m s@@ -102,6 +170,7 @@  {-# INLINE execWeightedT #-} +-- | Run a weighted computation, and return its result. evalWeighted     :: Semiring s     => Weighted s a -> a@@ -110,6 +179,7 @@  {-# INLINE evalWeighted #-} +-- | Run a weighted computation, and collect its weight. execWeighted     :: Semiring s     => Weighted s a -> s@@ -156,7 +226,8 @@ instance (Read w, Read1 m, Semiring w, Functor m) =>          Read1 (WeightedT w m) where     liftReadsPrec rp rl =-        readsData $ readsUnaryWith (liftReadsPrec rp' rl') "WeightedT" WeightedT+        readsData $+        readsUnaryWith (liftReadsPrec rp' rl') "WeightedT" WeightedT       where         rp' = liftReadsPrec2 rp rl readsPrec readList         rl' = liftReadList2 rp rl readsPrec readList@@ -185,7 +256,8 @@          Show (WeightedT w m a) where     showsPrec = showsPrec1 -instance (Semiring w, Monad m) => MonadWeighted w (WeightedT w m) where+instance (Semiring w, Monad m) =>+         MonadWeighted w (WeightedT w m) where     weighted (x,s) = WeightedT (pure (x, s))     {-# INLINE weighted #-}     weigh (WeightedT_ s) = WeightedT_ ((,) <$> s <*> get)@@ -194,5 +266,3 @@       where         scaleS = (=<<) (uncurry (<$) . fmap modify)     {-# INLINE scale #-}--
src/Control/Monad/Weighted/Class.hs view
@@ -2,7 +2,11 @@ {-# LANGUAGE FlexibleInstances      #-} {-# LANGUAGE UndecidableInstances   #-} -module Control.Monad.Weighted.Class where+module Control.Monad.Weighted.Class+  ( MonadWeighted(..)+  , collect+  , toCovector+  ) where  import qualified Control.Monad.Trans.Identity as Identity import qualified Control.Monad.Trans.Except as Except@@ -17,6 +21,8 @@  import Data.Coerce +-- | A class for computations which carry a weight with them. It is analogous+-- to 'Control.Monad.Writer.Writer' over the 'Data.Monoid.Product' 'Monoid'. class (Semiring w, Monad m) => MonadWeighted w m | m -> w where     {-# MINIMAL (weighted | weight), weigh, scale #-}     -- | @'weighted' (a,w)@ embeds a simple weighted action.@@ -73,6 +79,7 @@     weigh    = Reader.mapReaderT weigh     scale    = Reader.mapReaderT scale +-- | Collect the total weight of a computation. collect :: (Foldable m, MonadWeighted w m) => m a -> w collect = getAdd  #. foldMap (Add #. snd) . weigh @@ -80,5 +87,6 @@ (#.) :: Coercible b c => (b -> c) -> (a -> b) -> a -> c (#.) _ = coerce -toCont :: (Foldable m, MonadWeighted w m) => (a -> w) -> m a -> w-toCont f xs = collect (weight . f =<< xs)+-- | Transform a weighted computation to a covector.+toCovector :: (Foldable m, MonadWeighted w m) => m a -> (a -> w) -> w+toCovector xs f = collect (weight . f =<< xs)
src/Control/Monad/Weighted/Filter.hs view
@@ -1,13 +1,15 @@ {-# LANGUAGE FlexibleInstances          #-}+{-# LANGUAGE Strict                     #-} {-# LANGUAGE UndecidableInstances       #-} {-# LANGUAGE GeneralizedNewtypeDeriving #-} {-# LANGUAGE MultiParamTypeClasses      #-} {-# LANGUAGE PatternSynonyms            #-} {-# LANGUAGE ViewPatterns               #-} +-- | This module provides a weighted monad which filters out zero-weighted+-- results from a  computation at every opportunity. module Control.Monad.Weighted.Filter-  (catchZero-  ,FilterT+  (FilterT   ,pattern FilterT   ,runFilterT   ,evalFilterT@@ -29,25 +31,39 @@ import           Control.Monad.Weighted.Class import           Control.Monad.Writer.Class -import           Control.Arrow                (first) import           Data.Coerce import           Data.Monoid -catchZero :: (DetectableZero s, Alternative m) => (s -> m a) -> s -> m a-catchZero f s | isZero s = empty-              | otherwise = f s+first :: (a -> b) -> (a, c) -> (b, c)+first f (x, y) = (f x, y) -remZeroes :: (DetectableZero s, Alternative m, Monad m) => m (a, s) -> m (a, s)-remZeroes xs = xs >>=  (\(x,p) -> if isZero p then empty else pure (x,p))+catchZero+    :: (DetectableZero s, Alternative m)+    => (s -> m a) -> s -> m a+catchZero f s+  | isZero s = empty+  | otherwise = f s --- | Discards results which are zero-newtype FilterT s m a =-    FilterT_ { unFilterT :: StateT s m a }-    deriving (MonadTrans,MonadCont,MonadError e-             ,MonadReader r,MonadFix,MonadFail,MonadIO,Alternative,MonadPlus-             ,MonadWriter w)+{-# INLINE catchZero #-} -instance (Alternative m, DetectableZero s) => Functor (FilterT s m) where+remZeroes+    :: (DetectableZero s, Alternative m, Monad m)+    => m (a, s) -> m (a, s)+remZeroes xs =+    xs >>=+    (\(x,p) ->+          if isZero p+              then empty+              else pure (x, p))++-- | A weighted monad which discards results which are zero as it goes.+newtype FilterT s m a = FilterT_+    { unFilterT :: StateT s m a+    } deriving (MonadTrans,MonadCont,MonadError e,MonadReader r,MonadFix+               ,MonadFail,MonadIO,Alternative,MonadPlus,MonadWriter w)++instance (Alternative m, DetectableZero s) =>+         Functor (FilterT s m) where     fmap f (FilterT_ (StateT st)) =         (FilterT_ . StateT . catchZero) ((fmap . first) f . st)     {-# INLINE fmap #-}@@ -80,15 +96,18 @@                 s''     {-# INLINE (>>=) #-} +-- | Run a filtered computation in the underlying monad. runFilterT     :: (DetectableZero s, Alternative m, Monad m)     => FilterT s m a -> m (a, s)-runFilterT = remZeroes .+runFilterT =+    remZeroes .     (coerce :: (StateT s m a -> m (a, s)) -> FilterT s m a -> m (a, s))         (`runStateT` one)  {-# INLINE runFilterT #-} +-- | Evaluate a filtered computation in the underlying monad and return its result. evalFilterT     :: (Monad m, Semiring s)     => FilterT s m a -> m a@@ -98,6 +117,7 @@  {-# INLINE evalFilterT #-} +-- | Evaluate a filtered computation in the underlying monad and collect its weight. execFilterT     :: (Monad m, Semiring s)     => FilterT s m a -> m s@@ -107,11 +127,17 @@  {-# INLINE execFilterT #-} -pattern FilterT :: (Alternative m, DetectableZero s, Monad m) => m (a, s) -> FilterT s m a+-- | This pattern gives an interface to the 'FilterT' monad which makes it look as if+-- it were defined without the state monad.+pattern FilterT :: (Alternative m, DetectableZero s, Monad m) =>+        m (a, s) -> FilterT s m a+ pattern FilterT x <- (runFilterT -> x)-  where FilterT y = FilterT_ . StateT . catchZero $ \s -> (fmap.fmap) (s<.>) y+  where FilterT y+          = FilterT_ . StateT . catchZero $ \ s -> (fmap . fmap) (s <.>) y -instance (DetectableZero w, Monad m, Alternative m) => MonadWeighted w (FilterT w m) where+instance (DetectableZero w, Monad m, Alternative m) =>+         MonadWeighted w (FilterT w m) where     weighted (x,s) = FilterT (pure (x, s))     {-# INLINE weighted #-}     weigh (FilterT_ s) = FilterT_ ((,) <$> s <*> get)
weighted.cabal view
@@ -1,5 +1,5 @@ name:                weighted-version:             0.3.0.0+version:             0.3.0.1 synopsis:            Writer monad which uses semiring constraint description:         Writer monad which uses semiring constraint homepage:            https://github.com/oisdk/weighted