{-# LANGUAGE TypeFamilies #-} -- | Control flow constructs. module Control.Shell.Control ( module Control.Monad , Guard (..) , guard, when, unless, orElse ) where import Control.Shell.Internal import Control.Monad hiding (when, unless, guard) -- | Attempt to run the first command. If the first command fails, run the -- second. Forces serialization of the first command. orElse :: Shell a -> Shell a -> Shell a orElse a b = do ex <- try a case ex of Right x -> return x _ -> b class Guard guard where -- | The type of the guard's return value, if it succeeds. type Result guard -- | Perform a Shell computation; if the computation succeeds but returns -- a false-ish value, the outer Shell computation fails with the given -- error message. assert :: String -> guard -> Shell (Result guard) instance Guard (Either l r) where type Result (Either l r) = r assert _ (Right x) = return x assert desc _ = fail desc instance Guard (Maybe a) where type Result (Maybe a) = a assert _ (Just x) = return x assert desc _ = fail desc instance Guard Bool where type Result Bool = () assert _ True = return () assert desc _ = fail desc instance Guard a => Guard (Shell a) where type Result (Shell a) = Result a assert desc m = m >>= \x -> assert desc x -- | Perform a Shell computation; if the computation succeeds but returns -- a false-ish value, the outer Shell computation fails. -- Corresponds to 'CM.guard'. guard :: Guard g => g -> Shell (Result g) guard = assert "Guard failed!" -- | Perform the given computation if the given guard passes, otherwise do -- nothing. The guard raising an error counts as failure as far as this -- function is concerned. -- Corresponds to 'CM.when'. when :: Guard g => g -> Shell () -> Shell () when g m = do res <- try (guard g) case res of Right _ -> m _ -> return () -- | Perform the given computation if the given guard fails, otherwise do -- nothing. The guard raising an error counts as failure as far as this -- function is concerned. -- Corresponds to 'CM.unless'. unless :: Guard g => g -> Shell () -> Shell () unless g m = void (guard g) `orElse` m