{-# 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)