build-0.0.1: src/Build/Task/MonadPlus.hs
{-# LANGUAGE RankNTypes, TypeApplications #-}
-- | A version of monadic tasks with some support for non-determinism.
module Build.Task.MonadPlus (random, computeND, correctBuildValue) where
import Control.Monad
import Build.Task
import Build.Task.Wrapped
import Build.Store
-- | An example of a non-deterministic task: generate a random number from a
-- specified interval.
random :: (Int, Int) -> Task MonadPlus k Int
random (low, high) = const $ foldr mplus mzero $ map pure [low..high]
-- | Run a non-deterministic task with a pure lookup function, listing all
-- possible results.
computeND :: Task MonadPlus k v -> (k -> v) -> [v]
computeND task store = task (return . store)
-- | Given a description of @tasks@, an initial @store@, and a @result@ produced
-- by running a build system on a target @key@, this function returns 'True' if
-- the @key@'s value is a possible result of running the associated task.
correctBuildValue :: Eq v => Tasks MonadPlus k v -> Store i k v -> Store i k v -> k -> Bool
correctBuildValue tasks store result k = case tasks k of
Nothing -> getValue k result == getValue k store
Just t -> getValue k result `elem` computeND (unwrap @MonadPlus t) (flip getValue store)