----------------------------------------------------------------------------- -- Copyright 2019, Ideas project team. This file is distributed under the -- terms of the Apache License 2.0. For more information, see the files -- "LICENSE.txt" and "NOTICE.txt", which are included in the distribution. ----------------------------------------------------------------------------- -- | -- Maintainer : bastiaan.heeren@ou.nl -- Stability : provisional -- Portability : portable (depends on ghc) -- -- Constraints for constraint-based tutors -- ----------------------------------------------------------------------------- module Ideas.Common.Constraint ( Constraint, makeConstraint , isRelevant, isSatisfied, isViolated, getResult , Result(..), relevance ) where import Control.Applicative import Control.Monad import Ideas.Common.Id import Ideas.Common.View --------------------------------------------------------------------------- -- Constraint data Constraint a = C { constraintId :: Id , getResult :: a -> Result () } instance Show (Constraint a) where show = showId instance Eq (Constraint a) where r1 == r2 = constraintId r1 == constraintId r2 instance Ord (Constraint a) where compare = compareId instance HasId (Constraint a) where getId = constraintId changeId f r = r { constraintId = f (constraintId r) } instance LiftView Constraint where liftViewIn v (C n f) = C n (maybe Irrelevant (f . fst) . match v) makeConstraint :: IsId n => n -> (a -> Result ()) -> Constraint a makeConstraint = C . newId -- | Relevance condition isRelevant :: Constraint a -> a -> Bool isRelevant p a = case getResult p a of Irrelevant -> False _ -> True -- | Satisfaction condition isSatisfied :: Constraint a -> a -> Bool isSatisfied p a = case getResult p a of Ok _ -> True _ -> False -- | Satisfaction condition isViolated :: Constraint a -> a -> Maybe String isViolated p a = case getResult p a of Error s -> Just s _ -> Nothing --------------------------------------------------------------------------- -- Result data Result a = Irrelevant | Error String | Ok a deriving Show instance Functor Result where fmap _ Irrelevant = Irrelevant fmap _ (Error msg) = Error msg fmap f (Ok a) = Ok (f a) instance Applicative Result where pure = Ok Irrelevant <*> _ = Irrelevant Error msg <*> _ = Error msg Ok _ <*> Irrelevant = Irrelevant Ok _ <*> Error msg = Error msg Ok f <*> Ok a = Ok (f a) instance Alternative Result where empty = Error "" Irrelevant <|> r = r Error msg <|> Error _ = Error msg -- left-biased Error _ <|> r = r Ok a <|> _ = Ok a instance Monad Result where return = Ok fail = Error Irrelevant >>= _ = Irrelevant Error msg >>= _ = Error msg Ok a >>= f = f a instance MonadPlus Result where mzero = empty mplus = (<|>) -- | Turn errors into irrelevant results relevance :: Result a -> Result a relevance (Error _) = Irrelevant relevance r = r