{-# OPTIONS_GHC -fno-warn-orphans #-}
-- |
-- Copyright  : (c) Ivan Perez and Manuel Baerenz, 2016
-- License    : BSD3
-- Maintainer : ivan.perez@keera.co.uk
--
-- Instance of 'ArrowPlus' for Monadic Stream Functions ('MSF').
--
-- Import this module to include that (orphan) instance.
--
-- This is only defined for monads that are instances of 'MonadPlus'.
module Data.MonadicStreamFunction.Instances.ArrowPlus where

-- External imports
import Control.Applicative (Alternative (..))
import Control.Arrow       (ArrowPlus (..), ArrowZero (..))
import Control.Monad       (MonadPlus, mplus, mzero)

-- Internal imports
import Data.MonadicStreamFunction.Core         ()
import Data.MonadicStreamFunction.InternalCore (MSF (MSF, unMSF))

-- | Instance of 'ArrowZero' for Monadic Stream Functions ('MSF'). The monad
-- must be an instance of 'MonadPlus'.
instance (Monad m, MonadPlus m) => ArrowZero (MSF m) where
  zeroArrow :: forall b c. MSF m b c
zeroArrow = forall (m :: * -> *) a b. (a -> m (b, MSF m a b)) -> MSF m a b
MSF forall a b. (a -> b) -> a -> b
$ forall a b. a -> b -> a
const forall (m :: * -> *) a. MonadPlus m => m a
mzero

-- | Instance of 'ArrowPlus' for Monadic Stream Functions ('MSF'). The monad
-- must be an instance of 'MonadPlus'.
instance (Monad m, MonadPlus m) => ArrowPlus (MSF m) where
  MSF m b c
sf1 <+> :: forall b c. MSF m b c -> MSF m b c -> MSF m b c
<+> MSF m b c
sf2 = forall (m :: * -> *) a b. (a -> m (b, MSF m a b)) -> MSF m a b
MSF forall a b. (a -> b) -> a -> b
$ \b
a -> forall (m :: * -> *) a b. MSF m a b -> a -> m (b, MSF m a b)
unMSF MSF m b c
sf1 b
a forall (m :: * -> *) a. MonadPlus m => m a -> m a -> m a
`mplus` forall (m :: * -> *) a b. MSF m a b -> a -> m (b, MSF m a b)
unMSF MSF m b c
sf2 b
a

-- | Instance of 'Alternative' for Monadic Stream Functions ('MSF'),
-- implemented using the 'ArrowZero' and 'ArrowPlus' instances.
instance (Functor m, Monad m, MonadPlus m) => Alternative (MSF m a) where
  empty :: forall a. MSF m a a
empty = forall (a :: * -> * -> *) b c. ArrowZero a => a b c
zeroArrow
  <|> :: forall a. MSF m a a -> MSF m a a -> MSF m a a
(<|>) = forall (a :: * -> * -> *) b c.
ArrowPlus a =>
a b c -> a b c -> a b c
(<+>)