build-0.0.1: src/Build/Multi.hs
{-# 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"