packages feed

yield (empty) → 0.0.0.0

raw patch · 13 files changed

+618/−0 lines, 13 filesdep +basedep +containersdep +hspec

Dependencies added: base, containers, hspec, markdown-unlit, mtl, transformers, yield

Files

+ CHANGELOG.md view
@@ -0,0 +1,5 @@+## [_Unreleased_](https://github.com/freckle/yield/compare/v0.0.0.0...main)++## [v0.0.0.0](https://github.com/freckle/yield/tree/v0.0.0.0)++First tagged release.
+ LICENSE view
@@ -0,0 +1,21 @@+The MIT License (MIT)++Copyright (c) 2024 Renaissance Learning Inc++Permission is hereby granted, free of charge, to any person obtaining a copy+of this software and associated documentation files (the "Software"), to deal+in the Software without restriction, including without limitation the rights+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell+copies of the Software, and to permit persons to whom the Software is+furnished to do so, subject to the following conditions:++The above copyright notice and this permission notice shall be included in all+copies or substantial portions of the Software.++THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE+SOFTWARE.
+ README.lhs view
@@ -0,0 +1,42 @@+# Yield++<!--+```haskell+module Main (main) where++import Prelude+import Text.Markdown.Unlit ()+import Test.Hspec+```+-->++```haskell+import Control.Monad.Yield+```++```haskell+action1 :: MonadYield Char m => m Char+action1 = do+  yield 'a'+  yield 'b'+  pure 'c'+```++```haskell+action2 :: forall m. Monad m => m (String, Char)+action2 = runYieldT listAggregation action1+-- returns ("ab", 'c')+```++<!--+```haskell+main :: IO ()+main = hspec do+  it "" do+    action2 `shouldReturn` ("ab", 'c')+```+-->++---++[LICENSE](./LICENSE) | [CHANGELOG](./CHANGELOG.md)
+ README.md view
@@ -0,0 +1,42 @@+# Yield++<!--+```haskell+module Main (main) where++import Prelude+import Text.Markdown.Unlit ()+import Test.Hspec+```+-->++```haskell+import Control.Monad.Yield+```++```haskell+action1 :: MonadYield Char m => m Char+action1 = do+  yield 'a'+  yield 'b'+  pure 'c'+```++```haskell+action2 :: forall m. Monad m => m (String, Char)+action2 = runYieldT listAggregation action1+-- returns ("ab", 'c')+```++<!--+```haskell+main :: IO ()+main = hspec do+  it "" do+    action2 `shouldReturn` ("ab", 'c')+```+-->++---++[LICENSE](./LICENSE) | [CHANGELOG](./CHANGELOG.md)
+ library/Control/Monad/Trans/Codensity.hs view
@@ -0,0 +1,43 @@+{-# LANGUAGE UndecidableInstances #-}++module Control.Monad.Trans.Codensity+  ( CodensityT (..)+  ) where++import Control.Monad.IO.Class (MonadIO (..))+import Control.Monad.Reader (MonadReader (ask, local))+import Control.Monad.State (MonadState (state))+import Control.Monad.Trans.Class (MonadTrans (..))+import Control.Monad.Yield.Class (MonadYield (..))+import Data.Kind (Type)+import Prelude (Applicative (..), Functor (..), Monad (..), const, ($), (.))++-- | The "codensity transform", taken as an excerpt from the @kan-extensions@+--   package, following the model of @conduit@ to permit efficient monadic bind+newtype CodensityT (m :: Type -> Type) (a :: Type) = CodensityT {runCodensity :: forall b. (a -> m b) -> m b}++instance Functor (CodensityT m) where+  fmap f (CodensityT m) = CodensityT (\k -> m (k . f))++instance Applicative (CodensityT m) where+  pure x = CodensityT (\k -> k x)+  CodensityT f <*> CodensityT g = CodensityT (\bfr -> f (\ab -> g (bfr . ab)))++instance Monad (CodensityT m) where+  m >>= k = CodensityT (\c -> runCodensity m (\a -> runCodensity (k a) c))++instance MonadTrans CodensityT where+  lift m = CodensityT (m >>=)++instance MonadIO m => MonadIO (CodensityT m) where+  liftIO = lift . liftIO++instance MonadYield a m => MonadYield a (CodensityT m) where+  yield = lift . yield++instance MonadReader r m => MonadReader r (CodensityT m) where+  ask = CodensityT (ask >>=)+  local f m = CodensityT $ \c -> ask >>= \r -> local f . runCodensity m $ local (const r) . c++instance MonadState s m => MonadState s (CodensityT m) where+  state = lift . state
+ library/Control/Monad/Trans/Yield.hs view
@@ -0,0 +1,122 @@+{-# LANGUAGE UndecidableInstances #-}++module Control.Monad.Trans.Yield+  ( YieldT+  , runYieldT+  , hoistYieldT+  ) where++import Prelude++import Control.Monad (ap, liftM)+import Control.Monad.IO.Class (MonadIO (..))+import Control.Monad.Reader (MonadReader (..))+import Control.Monad.State (MonadState (..))+import Control.Monad.Trans.Class (MonadTrans (..))+import Control.Monad.Trans.Codensity (CodensityT (..))+import Control.Monad.Yield.Aggregation (Aggregation (..))+import Control.Monad.Yield.Class (MonadYield (..))++-- | Monad transformer that adds dynamically interpretable 'MonadYield' support+newtype YieldT a m r = YieldT (CodensityT (Yielder a m) r)+  deriving newtype (Functor, Applicative, Monad)++instance MonadTrans (YieldT a) where+  lift = YieldT . lift . lift++deriving newtype instance MonadIO m => MonadIO (YieldT a m)++deriving newtype instance Functor m => MonadYield a (YieldT a m)++deriving newtype instance MonadReader r m => MonadReader r (YieldT a m)++deriving newtype instance MonadState s m => MonadState s (YieldT a m)++-- | Transforms a 'YieldT''s base monad actions+hoistYieldT+  :: forall m n a r+   . Monad m+  => (forall x. m x -> n x)+  -> YieldT a m r+  -> YieldT a n r+hoistYieldT f (YieldT (CodensityT y0)) = YieldT $ CodensityT \continue ->+  let go = \case+        Pure r -> continue r+        Yield a y -> Yield a (go y)+        Act m -> Act (f $ liftM go $ collapse m)+         where+          collapse mpipe = do+            pipe' <- mpipe+            case pipe' of+              Act mpipe' -> collapse mpipe'+              _ -> pure pipe'+  in  go $ y0 Pure++-- | Runs a 'YieldT' computation in the base monad+runYieldT+  :: forall a b m r+   . Monad m+  => Aggregation m a b+  -- ^ What to do with the values emitted from the stream+  -> YieldT a m r+  -> m (b, r)+  -- ^ The result of aggregating of stream values, and the result of the 'YieldT'+runYieldT agg (YieldT (CodensityT y)) = runYielder agg (y Pure)++data Yielder a m r+  = Yield a (Yielder a m r)+  | Act (m (Yielder a m r))+  | Pure r+  deriving stock (Functor)++instance Functor m => Applicative (Yielder a m) where+  pure = Pure+  (<*>) = ap++instance Functor m => Monad (Yielder a m) where+  p0 >>= f = go p0+   where+    go p = case p of+      Yield a continue -> Yield a $ go continue+      Act m -> Act (go <$> m)+      Pure r -> f r++instance Functor m => MonadYield a (Yielder a m) where+  yield x = Yield x (Pure ())++instance MonadTrans (Yielder a) where+  lift = Act . fmap Pure++instance MonadIO m => MonadIO (Yielder a m) where+  liftIO = lift . liftIO++instance MonadReader r m => MonadReader r (Yielder a m) where+  ask = lift ask+  local f = hoistYielder $ local f++instance MonadState s m => MonadState s (Yielder a m) where+  state = lift . state++hoistYielder+  :: Functor n => (forall x. m x -> n x) -> Yielder a m r -> Yielder a n r+hoistYielder f p0 = go p0+ where+  go = \case+    Yield a p -> Yield a $ go p+    Act m -> Act $ go <$> f m+    Pure r -> Pure r++-- | Runs a 'Yielder' computation in the base monad+runYielder+  :: Monad m+  => Aggregation m a b+  -- ^ What to do with the values emitted from the stream+  -> Yielder a m r+  -> m (b, r)+  -- ^ The result of aggregating of stream values, and the result of the 'Yielder'+runYielder Aggregation {begin, step, done} p0 = begin >>= go p0+ where+  go p x = case p of+    Yield a continue -> (go continue $!) =<< step x a+    Act m -> m >>= \p' -> go p' x+    Pure r -> (,r) <$> done x
+ library/Control/Monad/Yield.hs view
@@ -0,0 +1,19 @@+module Control.Monad.Yield+  ( -- * Class+    MonadYield (..)++    -- * Monad transformer+  , YieldT+  , runYieldT+  , hoistYieldT++    -- * Aggregation+  , Aggregation (..)+  , noAggregation+  , seqAggregation+  , listAggregation+  ) where++import Control.Monad.Trans.Yield+import Control.Monad.Yield.Aggregation+import Control.Monad.Yield.Class
+ library/Control/Monad/Yield/Aggregation.hs view
@@ -0,0 +1,36 @@+module Control.Monad.Yield.Aggregation+  ( Aggregation (..)+  , noAggregation+  , seqAggregation+  , listAggregation+  ) where++import Data.Foldable (toList)+import Data.Sequence (Seq (..))+import Prelude (Applicative (..), Functor (..), (.), (<$>))++-- | An effectful stream consumer+--+-- The type parameter @x@ represents the consumer's internal state.+data Aggregation m a b = forall x.+  Aggregation+  { begin :: m x+  -- ^ Produce the initial state+  , step :: x -> a -> m x+  -- ^ Consume one item from the stream+  , done :: x -> m b+  -- ^ Produce the final result+  }++instance Functor m => Functor (Aggregation m a) where+  fmap f Aggregation {begin, step, done} =+    Aggregation {begin, step, done = fmap f . done}++noAggregation :: Applicative m => Aggregation m a ()+noAggregation = Aggregation {begin = pure (), step = \() _ -> pure (), done = pure}++seqAggregation :: Applicative m => Aggregation m a (Seq a)+seqAggregation = Aggregation {begin = pure Empty, step = \xs -> pure . (xs :|>), done = pure}++listAggregation :: Applicative m => Aggregation m a [a]+listAggregation = toList <$> seqAggregation
+ library/Control/Monad/Yield/Class.hs view
@@ -0,0 +1,9 @@+module Control.Monad.Yield.Class+  ( MonadYield (..)+  ) where++import Control.Monad (Monad)+import Data.Kind (Type)++class Monad m => MonadYield (a :: Type) (m :: Type -> Type) | m -> a where+  yield :: a -> m ()
+ package.yaml view
@@ -0,0 +1,88 @@+name: yield+version: 0.0.0.0+maintainer: Freckle Education+category: Streaming+github: freckle/yield+synopsis: YieldT monad transformer+description: |+  This package defines a class @MonadYield a@ for monads that can emit values+  values of type @a@ while they run, and a monad transformer @YieldT a@ which+  implements this class such that the emitted values can be captured in a+  streaming manner.++  This is an amalgamation of concepts from @pipes@, @conduit@, @foldl@, and+  @kan-extensions@, combined into a small self-contained package.++extra-doc-files:+  - README.md+  - CHANGELOG.md++extra-source-files:+  - package.yaml++language: GHC2021++ghc-options:+  - -Weverything+    -Wno-missing-kind-signatures+  - -Wno-all-missed-specialisations+  - -Wno-missed-specialisations+  - -Wno-missing-exported-signatures # re-enables missing-signatures+  - -Wno-missing-import-lists+  - -Wno-missing-local-signatures+  - -Wno-missing-safe-haskell-mode+  - -Wno-monomorphism-restriction+  - -Wno-prepositive-qualified-module+  - -Wno-safe+  - -Wno-unsafe++when:+  - condition: "impl(ghc >= 9.8)"+    ghc-options:+      - -Wno-missing-role-annotations+      - -Wno-missing-poly-kind-signatures++dependencies:+  - base < 5++default-extensions:+  - BlockArguments+  - DataKinds+  - DeriveAnyClass+  - DerivingVia+  - DerivingStrategies+  - FunctionalDependencies+  - GADTs+  - LambdaCase+  - NoImplicitPrelude+  - NoMonomorphismRestriction+  - OverloadedStrings+  - RecordWildCards+  - TypeFamilies++library:+  source-dirs: library+  other-modules:+    - Control.Monad.Trans.Codensity+  dependencies:+    - containers+    - mtl+    - transformers++tests:+  spec:+    main: Spec.hs+    source-dirs: tests+    ghc-options: -threaded -rtsopts "-with-rtsopts=-N"+    dependencies:+      - hspec+      - yield+      - mtl++  readme:+    main: README.lhs+    ghc-options: -pgmL markdown-unlit+    dependencies:+      - hspec+      - markdown-unlit+      - yield
+ tests/Spec.hs view
@@ -0,0 +1,1 @@+{-# OPTIONS_GHC -F -pgmF hspec-discover -Wno-missing-export-lists #-}
+ tests/YieldSpec.hs view
@@ -0,0 +1,66 @@+module YieldSpec (spec) where++import Prelude++import Control.Monad.Reader+import Control.Monad.State+import Control.Monad.Yield+import Data.Foldable+import Test.Hspec++spec :: Spec+spec = describe "YieldT" do+  describe "Trivial examples" do+    it "" $ runYieldT noAggregation (pure 'x') `shouldReturn` ((), 'x')+    it "" $ runYieldT listAggregation (pure 'x') `shouldReturn` ("", 'x')+    it "" $+      runYieldT listAggregation (yield 'a' >> pure 'x') `shouldReturn` ("a", 'x')+    it "" $+      runYieldT noAggregation (yield 'a' >> pure 'x') `shouldReturn` ((), 'x')+    it "" $+      runYieldT listAggregation (yield 'a' >> yield 'b' >> pure 'c')+        `shouldReturn` ("ab", 'c')++  describe "Monad instance" do+    it "" $+      runYieldT+        listAggregation+        (traverse_ @[] yield "ab" >> traverse @[] yield "cd" >> pure 'x')+        `shouldReturn` ("abcd", 'x')++  describe "MonadReader instance" do+    it "" $ runReaderT (runYieldT noAggregation ask) 'a' `shouldReturn` ((), 'a')+    it "" $+      runReaderT (runYieldT noAggregation (local succ ask)) 'a'+        `shouldReturn` ((), 'b')+    it "" $+      runReaderT+        ( runYieldT listAggregation do+            ask >>= yield+            local succ do+              ask >>= yield+              local succ do+                ask >>= yield+            ask >>= yield+        )+        'g'+        `shouldReturn` ("ghig", ())++  describe "MonadState instance" do+    it "" $ evalStateT (runYieldT noAggregation get) 'a' `shouldReturn` ((), 'a')+    it "" $+      evalStateT (runYieldT noAggregation (modify' succ >> get)) 'a'+        `shouldReturn` ((), 'b')+    it "" $+      evalStateT+        ( do+            (a, _) <- runYieldT listAggregation do+              get >>= yield+              modify' succ+              get >>= yield+              put 'x'+              get >>= yield+            gets (a,)+        )+        'g'+        `shouldReturn` ("ghx", 'x')
+ yield.cabal view
@@ -0,0 +1,124 @@+cabal-version:      1.18+name:               yield+version:            0.0.0.0+license:            MIT+license-file:       LICENSE+maintainer:         Freckle Education+homepage:           https://github.com/freckle/yield#readme+bug-reports:        https://github.com/freckle/yield/issues+synopsis:           YieldT monad transformer+description:+    This package defines a class @MonadYield a@ for monads that can emit values+    values of type @a@ while they run, and a monad transformer @YieldT a@ which+    implements this class such that the emitted values can be captured in a+    streaming manner.+    .+    This is an amalgamation of concepts from @pipes@, @conduit@, @foldl@, and+    @kan-extensions@, combined into a small self-contained package.++category:           Streaming+build-type:         Simple+extra-source-files: package.yaml+extra-doc-files:+    README.md+    CHANGELOG.md++source-repository head+    type:     git+    location: https://github.com/freckle/yield++library+    exposed-modules:+        Control.Monad.Trans.Yield+        Control.Monad.Yield+        Control.Monad.Yield.Aggregation+        Control.Monad.Yield.Class++    hs-source-dirs:     library+    other-modules:      Control.Monad.Trans.Codensity+    default-language:   GHC2021+    default-extensions:+        BlockArguments DataKinds DeriveAnyClass DerivingVia+        DerivingStrategies FunctionalDependencies GADTs LambdaCase+        NoImplicitPrelude NoMonomorphismRestriction OverloadedStrings+        RecordWildCards TypeFamilies++    ghc-options:+        -Weverything -Wno-missing-kind-signatures+        -Wno-all-missed-specialisations -Wno-missed-specialisations+        -Wno-missing-exported-signatures -Wno-missing-import-lists+        -Wno-missing-local-signatures -Wno-missing-safe-haskell-mode+        -Wno-monomorphism-restriction -Wno-prepositive-qualified-module+        -Wno-safe -Wno-unsafe++    build-depends:+        base >=4.16.4.0 && <5,+        containers >=0.6.5.1,+        mtl >=2.2.2,+        transformers >=0.5.6.2++    if impl(ghc >=9.8)+        ghc-options:+            -Wno-missing-role-annotations -Wno-missing-poly-kind-signatures++test-suite readme+    type:               exitcode-stdio-1.0+    main-is:            README.lhs+    other-modules:      Paths_yield+    default-language:   GHC2021+    default-extensions:+        BlockArguments DataKinds DeriveAnyClass DerivingVia+        DerivingStrategies FunctionalDependencies GADTs LambdaCase+        NoImplicitPrelude NoMonomorphismRestriction OverloadedStrings+        RecordWildCards TypeFamilies++    ghc-options:+        -Weverything -Wno-missing-kind-signatures+        -Wno-all-missed-specialisations -Wno-missed-specialisations+        -Wno-missing-exported-signatures -Wno-missing-import-lists+        -Wno-missing-local-signatures -Wno-missing-safe-haskell-mode+        -Wno-monomorphism-restriction -Wno-prepositive-qualified-module+        -Wno-safe -Wno-unsafe -pgmL markdown-unlit++    build-depends:+        base >=4.16.4.0 && <5,+        hspec >=2.9.7,+        markdown-unlit >=0.5.1,+        yield++    if impl(ghc >=9.8)+        ghc-options:+            -Wno-missing-role-annotations -Wno-missing-poly-kind-signatures++test-suite spec+    type:               exitcode-stdio-1.0+    main-is:            Spec.hs+    hs-source-dirs:     tests+    other-modules:+        YieldSpec+        Paths_yield++    default-language:   GHC2021+    default-extensions:+        BlockArguments DataKinds DeriveAnyClass DerivingVia+        DerivingStrategies FunctionalDependencies GADTs LambdaCase+        NoImplicitPrelude NoMonomorphismRestriction OverloadedStrings+        RecordWildCards TypeFamilies++    ghc-options:+        -Weverything -Wno-missing-kind-signatures+        -Wno-all-missed-specialisations -Wno-missed-specialisations+        -Wno-missing-exported-signatures -Wno-missing-import-lists+        -Wno-missing-local-signatures -Wno-missing-safe-haskell-mode+        -Wno-monomorphism-restriction -Wno-prepositive-qualified-module+        -Wno-safe -Wno-unsafe -threaded -rtsopts -with-rtsopts=-N++    build-depends:+        base >=4.16.4.0 && <5,+        hspec >=2.9.7,+        mtl >=2.2.2,+        yield++    if impl(ghc >=9.8)+        ghc-options:+            -Wno-missing-role-annotations -Wno-missing-poly-kind-signatures