{-# LANGUAGE DataKinds #-} {-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE GADTs #-} {-# LANGUAGE LambdaCase #-} {-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE TypeFamilies #-} {-# LANGUAGE TypeOperators #-} {-| Propositions and combinators for conveniently constructing them. -} module Language.Expression.Prop ( -- * Proposition Types Prop , Prop' -- * DSL , expr , plit , pnot , (*&&) , (*||) , (*->) , (*<->) , propAnd , propOr -- * HTraversable , LogicOp(..) ) where import Control.Applicative (liftA2) import Data.List (foldl') -- import Data.Typeable -- import Data.Functor.Classes import Data.Functor.Identity import Data.SBV import Language.Expression import Language.Expression.Choice import Language.Expression.Pretty import Language.Expression.Util -- | Propositions over general expressions. type Prop = HFree LogicOp -- | Propositions over expressions with the given list of operators. type Prop' ops v = Prop (HFree' ops v) -------------------------------------------------------------------------------- -- DSL -------------------------------------------------------------------------------- infixl 3 *&& infixl 2 *|| infixr 1 *-> infix 1 *<-> -- | Lift an expression into the land of propositions. expr :: expr a -> Prop expr a expr = HPure plit :: Bool -> Prop expr Bool plit = HWrap . LogLit pnot :: Prop expr Bool -> Prop expr Bool pnot = HWrap . LogNot (*&&) :: Prop expr Bool -> Prop expr Bool -> Prop expr Bool (*&&) = HWrap ... LogAnd (*||) :: Prop expr Bool -> Prop expr Bool -> Prop expr Bool (*||) = HWrap ... LogOr (*->) :: Prop expr Bool -> Prop expr Bool -> Prop expr Bool (*->) = HWrap ... LogImpl (*<->) :: Prop expr Bool -> Prop expr Bool -> Prop expr Bool (*<->) = HWrap ... LogEquiv propAnd :: [Prop expr Bool] -> Prop expr Bool propAnd [] = plit True propAnd (x : xs) = foldl' (*&&) x xs propOr :: [Prop expr Bool] -> Prop expr Bool propOr [] = plit False propOr (x : xs) = foldl' (*||) x xs -------------------------------------------------------------------------------- -- The HTraversable -------------------------------------------------------------------------------- -- | Logical operations data LogicOp t a where LogLit :: Bool -> LogicOp t Bool LogNot :: t Bool -> LogicOp t Bool LogAnd :: t Bool -> t Bool -> LogicOp t Bool LogOr :: t Bool -> t Bool -> LogicOp t Bool LogImpl :: t Bool -> t Bool -> LogicOp t Bool LogEquiv :: t Bool -> t Bool -> LogicOp t Bool instance HFunctor LogicOp instance HTraversable LogicOp where htraverse f = \case LogLit b -> pure $ LogLit b LogNot x -> LogNot <$> f x LogAnd x y -> LogAnd <$> f x <*> f y LogOr x y -> LogOr <$> f x <*> f y LogImpl x y -> LogImpl <$> f x <*> f y LogEquiv x y -> LogEquiv <$> f x <*> f y instance HFoldableAt Identity LogicOp where hfoldMap = implHfoldMap $ \case LogLit b -> pure b LogNot x -> not <$> x LogAnd x y -> liftA2 (&&) x y LogOr x y -> liftA2 (||) x y LogImpl x y -> liftA2 (||) (not <$> x) y LogEquiv x y -> liftA2 (&&) (liftA2 (||) (not <$> x) y) (liftA2 (||) (not <$> y) x) instance HFoldableAt SBV LogicOp where hfoldMap = implHfoldMap $ \case LogLit b -> fromBool b LogNot x -> sNot x LogAnd x y -> x .&& y LogOr x y -> x .|| y LogImpl x y -> x .=> y LogEquiv x y -> x .<=> y -- instance HEq LogicOp where -- liftHEq _ _ (LogLit x) (LogLit y) = x == y -- liftHEq le _ (LogNot x) (LogNot y) = le svEq x y -- liftHEq le _ (LogAnd x1 x2) (LogAnd y1 y2) = le svEq x1 y1 && le svEq x2 y2 -- liftHEq le _ (LogOr x1 x2) (LogOr y1 y2) = le svEq x1 y1 && le svEq x2 y2 -- liftHEq le _ (LogImpl x1 x2) (LogImpl y1 y2) = le svEq x1 y1 && le svEq x2 y2 -- liftHEq le _ (LogEquiv x1 x2) (LogEquiv y1 y2) = le svEq x1 y1 && le svEq x2 y2 -- liftHEq _ _ _ _ = False -- instance (Eq1 t) => Eq1 (LogicOp t) where liftEq = liftLiftEq -- instance (Eq a, Eq1 t) => Eq (LogicOp t a) where (==) = eq1 instance Pretty2 LogicOp where prettys2Prec p = \case LogLit True -> \r -> "T" ++ r LogLit False -> \r -> "F" ++ r LogNot x -> showParen (p > 8) $ showString "¬ " . prettys1Prec 9 x LogAnd x y -> showParen (p > 3) $ prettys1Prec 4 x . showString " ∧ " . prettys1Prec 4 y LogOr x y -> showParen (p > 2) $ prettys1Prec 3 x . showString " ∨ " . prettys1Prec 3 y LogImpl x y -> showParen (p > 1) $ prettys1Prec 2 x . showString " -> " . prettys1Prec 2 y LogEquiv x y -> showParen (p > 0) $ prettys1Prec 1 x . showString " <-> " . prettys1Prec 1 y -------------------------------------------------------------------------------- -- Internal Combinators -------------------------------------------------------------------------------- -- svEq :: (Typeable a, Typeable b, Eq a) => a -> b -> Bool -- svEq (x :: a) (y :: b) -- | Just Refl <- eqT :: Maybe (a :~: b) = x == y -- | otherwise = False