{-# LANGUAGE ImpredicativeTypes, ConstraintKinds #-}

-- | The Task abstractions.
module Build.Task (Task, Tasks, compose) where

import Control.Applicative

-- | A 'Task' is used to compute a value of type @v@, by finding the necessary
-- dependencies using the provided @fetch :: k -> f v@ callback.
type Task c k v = forall f. c f => (k -> f v) -> f v

-- | 'Tasks' associates a 'Task' with every non-input key. @Nothing@ indicates
-- that the key is an input.
type Tasks c k v = k -> Maybe (Task c k v)

-- | Compose two task descriptions, preferring the first one in case there are
-- two tasks corresponding to the same key.
compose :: Tasks Monad k v -> Tasks Monad k v -> Tasks Monad k v
compose :: forall k v. Tasks Monad k v -> Tasks Monad k v -> Tasks Monad k v
compose Tasks Monad k v
t1 Tasks Monad k v
t2 k
key = Tasks Monad k v
t1 k
key Maybe (Task Monad k v)
-> Maybe (Task Monad k v) -> Maybe (Task Monad k v)
forall a. Maybe a -> Maybe a -> Maybe a
forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
<|> Tasks Monad k v
t2 k
key