module Next.Producer.Examples
  (
    {- * Trivialities -} empty, singleton, effect, each,
    {- * Append -} append,
    {- * Unfold -} unfoldJob, unfoldEffect, unfoldPure,
  )
  where

import Essentials
import Next.Interface
import Next.Producer.Type

import SupplyChain (Job, Vendor (..), Referral (..))

import qualified Data.Foldable as Foldable
import qualified Data.List as List
import qualified SupplyChain.Job as Job

{-| The empty stream -}
empty :: forall up item action. ProducerPlus up action item
empty :: forall (up :: * -> *) item (action :: * -> *).
ProducerPlus up action item
empty = Vendor up (Next item) action
go
  where
    go :: Vendor up (Next item) action
    go :: Vendor up (Next item) action
go = forall (up :: * -> *) (down :: * -> *) (action :: * -> *).
(forall product.
 down product -> Job up action (Referral up down action product))
-> Vendor up down action
Vendor \Next item product
Next -> forall (f :: * -> *) a. Applicative f => a -> f a
pure forall a b. (a -> b) -> a -> b
$ forall (up :: * -> *) (down :: * -> *) (action :: * -> *) product.
product -> Vendor up down action -> Referral up down action product
Referral forall item. Step item
End Vendor up (Next item) action
go

{-| Yields one item, then stops -}
singleton :: forall up item action.
    Job up action item -> ProducerPlus up action item
singleton :: forall (up :: * -> *) item (action :: * -> *).
Job up action item -> ProducerPlus up action item
singleton Job up action item
x = forall (up :: * -> *) (down :: * -> *) (action :: * -> *).
(forall product.
 down product -> Job up action (Referral up down action product))
-> Vendor up down action
Vendor \Next item product
Next -> Job up action item
x forall (f :: * -> *) a b. Functor f => f a -> (a -> b) -> f b
<&> \item
y -> forall (up :: * -> *) (down :: * -> *) (action :: * -> *) product.
product -> Vendor up down action -> Referral up down action product
Referral (forall item. item -> Step item
Item item
y) forall (up :: * -> *) item (action :: * -> *).
ProducerPlus up action item
empty

{-| A single item obtained by performing an effect -}
effect :: forall up action item. action item -> ProducerPlus up action item
effect :: forall (up :: * -> *) (action :: * -> *) item.
action item -> ProducerPlus up action item
effect action item
x = forall (up :: * -> *) item (action :: * -> *).
Job up action item -> ProducerPlus up action item
singleton forall a b. (a -> b) -> a -> b
$ forall (action :: * -> *) product (up :: * -> *).
action product -> Job up action product
Job.perform action item
x

{-| Yields all the items from the given list -}
each :: forall up foldable item action. Foldable foldable =>
    foldable item -> ProducerPlus up action item
each :: forall (up :: * -> *) (foldable :: * -> *) item (action :: * -> *).
Foldable foldable =>
foldable item -> ProducerPlus up action item
each = forall (t :: * -> *) a. Foldable t => t a -> [a]
Foldable.toList forall {k} (cat :: k -> k -> *) (a :: k) (b :: k) (c :: k).
Category cat =>
cat a b -> cat b c -> cat a c
>>> forall state (up :: * -> *) item (action :: * -> *).
(state -> Step (item, state))
-> state -> ProducerPlus up action item
unfoldPure (forall a. [a] -> Maybe (a, [a])
List.uncons forall {k} (cat :: k -> k -> *) (a :: k) (b :: k) (c :: k).
Category cat =>
cat a b -> cat b c -> cat a c
>>> forall b a. b -> (a -> b) -> Maybe a -> b
maybe forall item. Step item
End forall item. item -> Step item
Item)

{-| Yields all the items of the first stream, followed by all the items of the second -}
append :: forall up item action. ProducerPlus up action item
    -> ProducerPlus up action item -> ProducerPlus up action item
append :: forall (up :: * -> *) item (action :: * -> *).
ProducerPlus up action item
-> ProducerPlus up action item -> ProducerPlus up action item
append ProducerPlus up action item
a ProducerPlus up action item
b = forall (up :: * -> *) (down :: * -> *) (action :: * -> *).
(forall product.
 down product -> Job up action (Referral up down action product))
-> Vendor up down action
Vendor \r :: Next item product
r@Next item product
Next -> forall (up :: * -> *) (down :: * -> *) (action :: * -> *).
Vendor up down action
-> forall product.
   down product -> Job up action (Referral up down action product)
handle ProducerPlus up action item
a Next item product
r forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \case
    Referral product
Step item
End ProducerPlus up action item
_ -> forall (up :: * -> *) (down :: * -> *) (action :: * -> *).
Vendor up down action
-> forall product.
   down product -> Job up action (Referral up down action product)
handle ProducerPlus up action item
b Next item product
r
    Referral (Item item
x) ProducerPlus up action item
a' -> forall (f :: * -> *) a. Applicative f => a -> f a
pure forall a b. (a -> b) -> a -> b
$ forall (up :: * -> *) (down :: * -> *) (action :: * -> *) product.
product -> Vendor up down action -> Referral up down action product
Referral (forall item. item -> Step item
Item item
x) (forall (up :: * -> *) item (action :: * -> *).
ProducerPlus up action item
-> ProducerPlus up action item -> ProducerPlus up action item
append ProducerPlus up action item
a' ProducerPlus up action item
b)

unfoldJob :: forall state up item action.
    (state -> Job up action (Step (item, state)))
    -> state -> ProducerPlus up action item
unfoldJob :: forall state (up :: * -> *) item (action :: * -> *).
(state -> Job up action (Step (item, state)))
-> state -> ProducerPlus up action item
unfoldJob state -> Job up action (Step (item, state))
f = state -> Vendor up (Next item) action
go
  where
    go :: state -> Vendor up (Next item) action
    go :: state -> Vendor up (Next item) action
go state
s = forall (up :: * -> *) (down :: * -> *) (action :: * -> *).
(forall product.
 down product -> Job up action (Referral up down action product))
-> Vendor up down action
Vendor \r :: Next item product
r@Next item product
Next -> state -> Job up action (Step (item, state))
f state
s forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \case
        Step (item, state)
End -> forall (up :: * -> *) (down :: * -> *) (action :: * -> *).
Vendor up down action
-> forall product.
   down product -> Job up action (Referral up down action product)
handle forall (up :: * -> *) item (action :: * -> *).
ProducerPlus up action item
empty Next item product
r
        Item (item
x, state
s') -> forall (f :: * -> *) a. Applicative f => a -> f a
pure forall a b. (a -> b) -> a -> b
$ forall (up :: * -> *) (down :: * -> *) (action :: * -> *) product.
product -> Vendor up down action -> Referral up down action product
Referral (forall item. item -> Step item
Item item
x) (state -> Vendor up (Next item) action
go state
s')

unfoldEffect :: forall state up item action.
    (state -> action (Step (item, state)))
    -> state -> ProducerPlus up action item
unfoldEffect :: forall state (up :: * -> *) item (action :: * -> *).
(state -> action (Step (item, state)))
-> state -> ProducerPlus up action item
unfoldEffect state -> action (Step (item, state))
f = forall state (up :: * -> *) item (action :: * -> *).
(state -> Job up action (Step (item, state)))
-> state -> ProducerPlus up action item
unfoldJob (forall (action :: * -> *) product (up :: * -> *).
action product -> Job up action product
Job.perform forall {k} (cat :: k -> k -> *) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. state -> action (Step (item, state))
f)

unfoldPure :: forall state up item action.
    (state -> Step (item, state))
    -> state -> ProducerPlus up action item
unfoldPure :: forall state (up :: * -> *) item (action :: * -> *).
(state -> Step (item, state))
-> state -> ProducerPlus up action item
unfoldPure state -> Step (item, state)
f = forall state (up :: * -> *) item (action :: * -> *).
(state -> Job up action (Step (item, state)))
-> state -> ProducerPlus up action item
unfoldJob (forall (f :: * -> *) a. Applicative f => a -> f a
pure forall {k} (cat :: k -> k -> *) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. state -> Step (item, state)
f)