module Catch where -- A property of Catch by Neil Mitchell import Data.List import Data.Maybe -- Property data Prop a = Or [Prop a] | And [Prop a] | Lit a andP = And orP = Or lit = Lit true = And [] -- Constraints data Sat a = Sat a Constraint substP :: Eq alpha => [(alpha,beta)] -> Prop (Sat alpha) -> Prop (Sat beta) substP xs (Lit (Sat i k)) = Lit $ Sat (fromJust $ lookup i xs) k substP xs (And p) = And $ map (substP xs) p substP xs (Or p) = Or $ map (substP xs) p -- MP constraints type Constraint = [Val] data Val = [Pattern] :* [Pattern] | Any deriving (Show,Eq) data Pattern = Pattern CtorName [Val] deriving (Show,Eq) (<|) :: CtorName -> Constraint -> Prop (Sat Int) c <| vs = orP (map f vs) where (rec,non) = partition (isRec . (,) c) [0..arity c-1] f Any = true f (ms_1 :* ms_2) = orP [ andP $ map lit $ g vs_1 | Pattern c_1 vs_1 <- ms_1, c_1 == c] where g vs = zipWith Sat non (map (:[]) vs) ++ map (`Sat` [ms_2 :* ms_2]) rec mergeVal :: Val -> Val -> Val (a_1 :* b_1) `mergeVal` (a_2 :* b_2) = merge a_1 a_2 :* merge b_1 b_2 x `mergeVal` y = if x == Any then y else x merge :: [Pattern] -> [Pattern] -> [Pattern] merge ms_1 ms_2 = [Pattern c_1 (zipWith mergeVal vs_1 vs_2) | Pattern c_1 vs_1 <- ms_1, Pattern c_2 vs_2 <- ms_2, c_1 == c_2] validConstraint = all validVal validVal Any = True validVal (ms1 :* ms2) = validPatterns ms1 && validPatterns ms2 validPatterns = all validPattern validPattern (Pattern c xs) = (fields c == length xs) && all validVal xs -- Evaluator data Value = Value CtorName [Value] | Bottom deriving (Eq,Show) sat :: Sat Value -> Bool sat (Sat Bottom k) = True sat (Sat (Value c xs) k) = sat' $ substP (zip [0..] xs) (c <| k) sat' :: Prop (Sat Value) -> Bool sat' (And xs) = all sat' xs sat' (Or xs) = any sat' xs sat' (Lit x) = sat x -- Core language data CtorName = Ctor | CtorN | CtorR | CtorNR deriving (Show,Eq) arity Ctor = 0 arity CtorN = 1 arity CtorR = 1 arity CtorNR = 2 fields Ctor = 0 fields CtorN = 1 fields CtorR = 0 fields CtorNR = 1 isRec (CtorR, 0) = True isRec (CtorNR, 1) = True isRec _ = False validValue :: Value -> Bool validValue Bottom = True validValue (Value c xs) = (arity c == length xs) && all validValue xs -- Properties infixr 0 --> False --> _ = True True --> x = x prop :: (Value, [Pattern], [Pattern]) -> Bool prop (v,ms1,ms2) = (validValue v && validPatterns ms1 && validPatterns ms2 && sat (Sat v [ms :* ms])) --> sat (Sat v [ms1 :* ms2]) where ms = merge ms1 ms2