{-# LANGUAGE RankNTypes #-} -- | Given a build system that can work with single keys, generalise that to one -- that deals with multiple keys at a time. module Build.Multi (multi) where import Data.Maybe import Build.Task -- | Defines a set partition. For a function to be a valid partition, -- if @f k == ks@, then: -- -- * @k \in ks@ -- -- * @forall i \in ks . f i == ks@ type Partition k = k -> [k] -- | Given a build rule where you can build some combinations of multiple rules, -- use a partition to enable building lots of multiple rule subsets. multi :: Eq k => Partition k -> Tasks Applicative [k] [v] -> Tasks Applicative [k] [v] multi partition tasks keys | k:_ <- keys, partition k == keys = tasks keys | otherwise = Just $ \fetch -> sequenceA [ select k <$> fetch (partition k) | k <- keys ] where select k = fromMaybe (error msg) . lookup k . zip (partition k) msg = "Partition invariants violated"