{-# LANGUAGE ConstraintKinds, DeriveFunctor, FlexibleInstances #-} {-# LANGUAGE RankNTypes, StandaloneDeriving #-} -- | This whole module is just a tiresome workaround for the lack of impredicative -- polymorphism. If GHC adds impredicative polymorphism, we can drop it entirely -- and simplify the rest of the code by removing unnecessary task unwrapping. module Build.Task.Wrapped (GTask (..), Wrapped, unwrap) where import Control.Applicative import Control.Monad import Build.Task -- | GTask is a generalised Task wrapped in a newtype. It is generalised in the -- sense that it computes a value of type @a@ given a fetch of type @k -> f v@. newtype GTask c k v a = GTask { runGTask :: forall f. c f => (k -> f v) -> f a } type Wrapped c k v = (k -> GTask c k v v) -> GTask c k v v unwrap :: forall c k v. Wrapped c k v -> Task c k v unwrap wrapped = runGTask (wrapped f) where f :: k -> GTask c k v v f k = GTask $ \f -> f k -- Thanks to the generalisation, we can make GTask an instance of many classes deriving instance Functor (GTask Functor k v) deriving instance Functor (GTask Applicative k v) deriving instance Functor (GTask Alternative k v) deriving instance Functor (GTask Monad k v) deriving instance Functor (GTask MonadPlus k v) instance Applicative (GTask Applicative k v) where pure x = GTask $ \_ -> pure x GTask f <*> GTask x = GTask $ \fetch -> f fetch <*> x fetch instance Applicative (GTask Alternative k v) where pure x = GTask $ \_ -> pure x GTask f <*> GTask x = GTask $ \fetch -> f fetch <*> x fetch instance Applicative (GTask Monad k v) where pure x = GTask $ \_ -> pure x GTask f <*> GTask x = GTask $ \fetch -> f fetch <*> x fetch instance Applicative (GTask MonadPlus k v) where pure x = GTask $ \_ -> pure x GTask f <*> GTask x = GTask $ \fetch -> f fetch <*> x fetch instance Monad (GTask Monad k v) where return x = GTask $ \_ -> return x GTask x >>= f = GTask $ \fetch -> x fetch >>= \a -> runGTask (f a) fetch instance Monad (GTask MonadPlus k v) where return x = GTask $ \_ -> return x GTask x >>= f = GTask $ \fetch -> x fetch >>= \a -> runGTask (f a) fetch instance Alternative (GTask Alternative k v) where empty = GTask $ \_ -> empty GTask x <|> GTask y = GTask $ \fetch -> x fetch <|> y fetch instance Alternative (GTask MonadPlus k v) where empty = GTask $ \_ -> empty GTask x <|> GTask y = GTask $ \fetch -> x fetch <|> y fetch instance MonadPlus (GTask MonadPlus k v) where mzero = empty mplus = (<|>)