-- | Description: an /effect/ is either /request/ or /perform/

module SupplyChain.Core.Effect
  (
    {- * Type -} Effect (Request, Perform),
    {- * Running -} run, absurd,
    {- * Alteration -} alterRequest, alterPerform,
  )
  where

import Data.Functor.Const (Const)
import Data.Void (Void)

data Effect up action product =
    Request (up product) | Perform (action product)

run :: Effect (Const Void) action product -- ^ An effect that makes no requests
    -> action product
run :: forall {k} (action :: k -> *) (product :: k).
Effect (Const Void) action product -> action product
run = \case
    Perform action product
x -> action product
x
    Request Const Void product
x -> case Const Void product
x of {}

absurd ::
    Effect (Const Void) (Const Void) x -- ^ There are values of this type.
    -> product
absurd :: forall {k} (x :: k) product.
Effect (Const Void) (Const Void) x -> product
absurd = \case
    Perform Const Void x
x -> case Const Void x
x of {}
    Request Const Void x
x -> case Const Void x
x of {}

alterRequest ::
    (up product -> Effect up' action product) -- ^ Modification to requests
    -> Effect up action product -> Effect up' action product
alterRequest :: forall {k} (up :: k -> *) (product :: k) (up' :: k -> *)
       (action :: k -> *).
(up product -> Effect up' action product)
-> Effect up action product -> Effect up' action product
alterRequest up product -> Effect up' action product
f = \case
    Perform action product
x -> forall {k} (up :: k -> *) (action :: k -> *) (product :: k).
action product -> Effect up action product
Perform action product
x
    Request up product
x -> up product -> Effect up' action product
f up product
x

alterPerform ::
    (action product -> Effect up action' product) -- ^ Modification to actions
    -> Effect up action product -> Effect up action' product
alterPerform :: forall {k} (action :: k -> *) (product :: k) (up :: k -> *)
       (action' :: k -> *).
(action product -> Effect up action' product)
-> Effect up action product -> Effect up action' product
alterPerform action product -> Effect up action' product
f = \case
    Request up product
x -> forall {k} (up :: k -> *) (action :: k -> *) (product :: k).
up product -> Effect up action product
Request up product
x
    Perform action product
x -> action product -> Effect up action' product
f action product
x