{-# LANGUAGE Arrows, MultiParamTypeClasses, FlexibleInstances, FlexibleContexts, ExistentialQuantification, Rank2Types #-} module RSAGL.FRP.FactoryArrow (FactoryArrow(..)) where import Prelude hiding ((.),id) import Control.Arrow import Control.Monad import Control.Monad.Fix import Control.Category -- | An 'Arrow' that constructs an associated monadic computation. newtype FactoryArrow m n i o = FactoryArrow { runFactory :: m (Kleisli n i o) } instance (Monad m,Monad n) => Category (FactoryArrow m n) where (FactoryArrow a) . (FactoryArrow b) = FactoryArrow $ do b' <- b a' <- a return $ a' . b' id = FactoryArrow $ return id instance (Monad m,Monad n) => Arrow (FactoryArrow m n) where arr = FactoryArrow . return . arr first = FactoryArrow . liftM first . runFactory second = FactoryArrow . liftM second . runFactory instance (Monad m,MonadFix n) => ArrowLoop (FactoryArrow m n) where loop = FactoryArrow . liftM loop . runFactory -- | Careful! To implement ArrowApply, the factory action must run imbedded in the constructed action. instance (Monad m) => ArrowApply (FactoryArrow m m) where app = factoryApp id -- | Implements ArrowApply for any FactoryArrow capable of it, -- but this requires a way to lift operations in m into n. factoryApp :: (Monad m,Monad n) => (forall a. m a -> n a) -> FactoryArrow m n (FactoryArrow m n i o,i) o factoryApp liftM2N = FactoryArrow $ return $ Kleisli $ \(FactoryArrow m,i) -> do (Kleisli n) <- liftM2N m n i -- | A choice is constructed at factory time whether or not the constructed action is ever evaluated. instance (Monad m,Monad n) => ArrowChoice (FactoryArrow m n) where left = FactoryArrow . liftM left . runFactory right = FactoryArrow . liftM right . runFactory instance (Monad m,MonadPlus n) => ArrowZero (FactoryArrow m n) where zeroArrow = FactoryArrow $ return zeroArrow -- | As with ArrowChoice, both branches are constructed at factory time whether or not the constructed actions are ever evaluated. instance (Monad m,MonadPlus n) => ArrowPlus (FactoryArrow m n) where a <+> b = FactoryArrow $ liftM2 (<+>) (runFactory a) (runFactory b)