-- | Validated values -- -- 'Validated' is similar to 'Feldspar.Option.Option', with the difference that -- 'Validated' does not guarantee that invalid values are not evaluated. -- Therefore, 'Validated' should not be used to guard operations from illegal -- use (e.g. array bounds checking). -- -- Still, the operations try to defer evaluation of invalid values as much as -- possible. module Feldspar.Data.Validated where -- Since there's no guarantee that invalid values are not evaluated, there is -- no point in hiding the implementation. Having access to the implementation -- means that it's possible to take shortcuts. For example, `fmap` could not -- have been implemented without opening up the representation. import Prelude () import Language.Syntactic import Feldspar hiding (desugar, sugar) import Feldspar.Representation -- | A value that can be valid or invalid data Validated a = Validated (Data Bool) a instance Functor Validated where fmap f (Validated valid a) = Validated valid (f a) instance Applicative Validated where pure = return (<*>) = ap instance Monad Validated where return = Validated true Validated valid a >>= k = Validated (valid && valid') b where Validated valid' b = k a instance Syntax a => Syntactic (Validated a) where type Domain (Validated a) = FeldDomain type Internal (Validated a) = (Bool, Internal a) desugar (Validated valid a) = desugar (valid,a) sugar = uncurry Validated . sugar -- | Create a validated value. Note that the value may get evaluated even if the -- condition is false. validWhen :: Data Bool -> a -> Validated a validWhen = Validated -- | Invalid value invalid :: Syntax a => Validated a invalid = Validated false example -- | Deconstruct an 'Validated' value validated :: Syntax b => b -- ^ Invalid case -> (a -> b) -- ^ Valid case -> Validated a -> b validated no yes (Validated valid a) = valid ? yes a $ no -- | Deconstruct an 'Validated' value caseValidated :: Syntax b => Validated a -> b -- ^ Invalid case -> (a -> b) -- ^ Valid case -> b caseValidated v no yes = validated no yes v fromValidated :: Syntax a => Validated a -> a -- ^ Value to return in case the first arg. is invalid -> a fromValidated v def = caseValidated v def id -- | Deconstruct an 'Validated' value validatedM :: MonadComp m => m () -- ^ Invalid case -> (a -> m ()) -- ^ Valid case -> Validated a -> m () validatedM no yes (Validated valid a) = iff valid (yes a) no -- | Deconstruct an 'Validated' value caseValidatedM :: MonadComp m => Validated a -> m () -- ^ Invalid case -> (a -> m ()) -- ^ Valid case -> m () caseValidatedM v no yes = validatedM no yes v