packages feed

funflow-1.6.0: src/Control/Funflow/Class.hs

{-# LANGUAGE FlexibleContexts       #-}
{-# LANGUAGE FlexibleInstances      #-}
{-# LANGUAGE FunctionalDependencies #-}
{-# LANGUAGE MultiParamTypeClasses  #-}
{-# LANGUAGE TypeSynonymInstances   #-}

-- | Defines a class for types which can be used as workflows.
--
--   In general, you should not need this functionality unless you are defining
--   your own flow types (perhaps to use a state transformer or similar), in
--   which case this allows you to work using the standard combinators in
--   Funflow and then define the mapping to 'Base.Flow'
--
--   For an example of use, see the module @Control.Funflow.Checkpoints@, which
--   defines a checkpointed flow.
module Control.Funflow.Class where

import           Control.Arrow
import           Control.Arrow.Free
import qualified Control.Funflow.Base            as Base
import           Control.Funflow.External
import           Data.CAS.ContentHashable
import qualified Data.CAS.ContentStore           as CS
import qualified Data.Profunctor.Cayley          as P
import           Data.Default                    (def)
import           Path

class (Arrow arr, ArrowError ex arr) => ArrowFlow eff ex arr | arr -> eff ex where
  -- | Create a flow from a pure function.
  step' :: Base.Properties a b -> (a -> b) -> arr a b
  -- | Create a flow from an IO action.
  stepIO' :: Base.Properties a b -> (a -> IO b) -> arr a b
  -- | Create an external task in the flow.
  external :: (a -> ExternalTask) -> arr a CS.Item
  -- | Create an external task with additional properties
  external' :: Base.ExternalProperties a -> (a -> ExternalTask) -> arr a CS.Item
  -- | Create a flow from a user-defined effect.
  wrap' :: Base.Properties a b -> eff a b -> arr a b
  -- | Create a flow which will write its incoming data to the store.
  putInStore :: ContentHashable IO a => (Path Abs Dir -> a -> IO ()) -> arr a CS.Item
  -- | Create a flow which will read data from the given store item.
  getFromStore :: (Path Abs t -> IO a) -> arr (CS.Content t) a
  -- | Perform some internal manipulation of the content store.
  internalManipulateStore :: (CS.ContentStore -> a -> IO b) -> arr a b

instance ArrowFlow eff ex (Base.Flow eff ex) where
  step' props = effect . Base.Step props
  stepIO' props = effect . Base.StepIO props
  external = effect . Base.External def
  external' p td = effect $ Base.External p td
  wrap' p eff = effect $ Base.Wrapped p eff
  putInStore = effect . Base.PutInStore
  getFromStore = effect . Base.GetFromStore
  internalManipulateStore = effect . Base.InternalManipulateStore

-- | Create a flow from a pure function.
--   This is a variant on 'step'' which uses the default properties.
step :: ArrowFlow eff ex arr => (a -> b) -> arr a b
step = step' def

-- | Create a flow from an IO action.
--   This is a variant on 'stepIO'' which uses the default properties.
stepIO :: ArrowFlow eff ex arr => (a -> IO b) -> arr a b
stepIO = stepIO' def

wrap :: ArrowFlow eff ex arr => eff a b -> arr a b
wrap = wrap' def

instance ( Applicative app
         , ArrowError ex (arr eff ex)
         , ArrowFlow eff ex (arr eff ex) )
      => ArrowFlow eff ex (P.Cayley app (arr eff ex)) where
  step' props f = P.Cayley . pure $ step' props f
  stepIO' props f = P.Cayley . pure $ stepIO' props f
  external f = P.Cayley . pure $ external f
  external' props f = P.Cayley . pure $ external' props f
  wrap' props eff = P.Cayley . pure $ wrap' props eff
  putInStore f = P.Cayley . pure $ putInStore f
  getFromStore f = P.Cayley . pure $ getFromStore f
  internalManipulateStore f = P.Cayley . pure $ internalManipulateStore f