zsyntax-0.2.0.0: src/Zsyntax/Labelled/Formula.hs
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE StandaloneDeriving #-}
{-# LANGUAGE ExistentialQuantification #-}
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE DeriveFunctor #-}
{-# LANGUAGE DeriveFoldable #-}
{-# LANGUAGE DeriveTraversable #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# OPTIONS_GHC -Wno-unticked-promoted-constructors #-}
module Zsyntax.Labelled.Formula
( FKind(..)
, Label(..)
, ElemBase(..)
, ReactionList
-- * Labelled formulas
, LFormula(..)
, ppLFormula
, elemBase
, label
, frmlHetEq
, frmlHetOrd
, deepHetComp
-- * Labelled axioms
, LAxiom(..)
, axLabel
, axToFormula
, ppLAxiom
-- * Opaque formulas
, Opaque(..)
, withOpaque
, oConj
, oImpl
-- * Basic formulas
, BFormula(..)
, bAtom
, bConj
, bfToFormula
, bfToAtoms
, maybeBFormula
) where
import Zsyntax.ReactionList
import Data.MultiSet (MultiSet, singleton)
import Data.Foldable (fold)
import Data.List.NonEmpty (NonEmpty(..))
newtype ElemBase a = ElemBase { unEB :: MultiSet a }
deriving (Semigroup, Monoid, Eq, Ord, Show)
data FKind = KAtom | KConj | KImpl
type ReactionList a = RList (ElemBase a) (CtrlSet a)
-- | Type of labelled formulas, indexed by a formula kind and parameterized by
-- the type of the labels and of the logical atoms.
data LFormula :: FKind -> * -> * -> * where
Atom :: a -> LFormula KAtom a l
Conj
:: LFormula k1 a l
-> LFormula k2 a l
-> l
-> LFormula KConj a l
Impl
:: LFormula k1 a l
-> ElemBase a
-> ReactionList a
-> LFormula k2 a l
-> l
-> LFormula KImpl a l
deriving instance (Show a, Show l) => Show (LFormula k a l)
-- | Heterogeneous equality test between labelled formulas.
--
-- This function just compares the formulas' labels for equality, under the
-- assumption that labels have been assigned in a sensible way.
frmlHetEq :: (Eq a, Eq l) => LFormula k1 a l -> LFormula k2 a l -> Bool
frmlHetEq f1 f2 = label f1 == label f2
-- | Heterogeneous comparison between labelled formulas.
--
-- This function just compares the formulas' labels, under the assumption that
-- labels have been assigned in a sensible way.
frmlHetOrd :: (Ord a, Ord l) => LFormula k1 a l -> LFormula k2 a l -> Ordering
frmlHetOrd f1 f2 = compare (label f1) (label f2)
foldF
:: (a -> b)
-> (b -> b -> l -> b)
-> (b -> ElemBase a -> ReactionList a -> b -> l -> b)
-> LFormula k a l -> b
foldF f _ _ (Atom a) = f a
foldF f g h (Conj f1 f2 l) = g (foldF f g h f1) (foldF f g h f2) l
foldF f g h (Impl f1 eb cty f2 l) = h (foldF f g h f1) eb cty (foldF f g h f2) l
deriving instance Functor (LFormula k a)
deriving instance Foldable (LFormula k a)
deriving instance Traversable (LFormula k a)
-- | Pretty-print labelled formulas, given a way to pretty-print its atoms.
--
-- Note that this function ignores labels, for which one should use the 'Show'
-- instance.
ppLFormula :: (a -> String) -> LFormula k a l -> String
ppLFormula p = foldF p (\a b _ -> fold [a, " ⊗ ", b])
(\a _ _ b _ -> fold ["(", a, " → ", b, ")"])
-- | Returns the elementary base of a labelled formula.
elemBase :: Ord a => LFormula k a l -> ElemBase a
elemBase = foldF (ElemBase . singleton) (\a b _ -> a <> b) (\_ e _ _ _ -> e)
--------------------------------------------------------------------------------
-- Opaque formulas
-- | Type of opaque formulas, that is, those for which we do not care about
-- their formula kind.
data Opaque a l = forall k . O (LFormula k a l)
deriving instance (Show a, Show l) => Show (Opaque a l)
instance (Eq l, Eq a) => Eq (Opaque a l) where
O f1 == O f2 = frmlHetEq f1 f2
instance (Ord l, Ord a) => Ord (Opaque a l) where
compare (O f1) (O f2) = frmlHetOrd f1 f2
withOpaque :: (forall k . LFormula k a l -> b) -> Opaque a l -> b
withOpaque f (O fr) = f fr
-- | Constructs the conjunction of two opaque formulas. The result is a provably
-- conjunctive labelled formula.
oConj :: Opaque a l -> Opaque a l -> l -> LFormula KConj a l
oConj (O f1) (O f2) = Conj f1 f2
-- | Constructs the Zsyntax conditional (aka linear implication) between two
-- opaque formulas, whose reaction is described by a given elementary base and
-- reaction list. The result is a provably implicational labelled formula.
oImpl :: Opaque a l -> ElemBase a -> ReactionList a -> Opaque a l -> l
-> LFormula KImpl a l
oImpl (O f1) eb cty (O f2) = Impl f1 eb cty f2
--------------------------------------------------------------------------------
-- Basic formulas
-- | Type of basic formulas.
-- A basic formula is one composed of conjunctions of atoms.
data BFormula a l = BAtom a | BConj (BFormula a l) (BFormula a l) l
deriving (Functor, Foldable, Traversable, Show)
-- | Constructs a basic formula from a logical atom.
bAtom :: a -> BFormula a l
bAtom = BAtom
-- | Constructs the conjunction of two basic formulas, with a given label.
bConj :: l -> BFormula a l -> BFormula a l -> BFormula a l
bConj l f1 f2 = BConj f1 f2 l
-- data ExBFormula a l = forall k . ExBFormula (LFormula k a l)
-- | Returns the labelled formula corresponding to a given basic formula.
--
-- Note that the result formula is opaque, since it could be an atom as well as
-- a conjunction, and thus has no determined index.
bfToFormula :: BFormula a l -> Opaque a l
bfToFormula (BAtom x) = O (Atom x)
bfToFormula (BConj f1 f2 l) = O (oConj (bfToFormula f1) (bfToFormula f2) l)
-- | Unrolls a basic formula, discarding all labels and returning a (non-empty)
-- list of all its constituent logical atoms.
bfToAtoms :: BFormula a l -> NonEmpty a
bfToAtoms (BAtom bf) = bf :| []
bfToAtoms (BConj f1 f2 _) = bfToAtoms f1 <> bfToAtoms f2
-- | Decides whether the input labelled formula is a basic formula, and if so,
-- it returns it wrapped in 'Just' as a proper basic formula.
maybeBFormula :: LFormula k a l -> Maybe (BFormula a l)
maybeBFormula (Atom x) = pure (BAtom x)
maybeBFormula (Conj f1 f2 l) =
BConj <$> maybeBFormula f1 <*> maybeBFormula f2 <*> pure l
maybeBFormula Impl {} = Nothing
-- was: decideF
--------------------------------------------------------------------------------
data LAxiom a l = LAx (BFormula a l) (ReactionList a) (BFormula a l) l
deriving (Show, Functor, Foldable, Traversable)
-- | Converts a labelled axiom to a labelled formula.
axToFormula :: Ord a => LAxiom a l -> LFormula KImpl a l
axToFormula (LAx f1 _ f2 l) = case (bfToFormula f1, bfToFormula f2) of
(O f1', O f2') ->
Impl (mapCty (const mempty) f1') mempty mempty (mapCty (const mempty) f2') l
-- | Pretty-prints a labelled axiom, given a way to pretty-print its atoms.
--
-- Note that this function ignores labels, for which one should rely on the
-- 'Show' instance.
ppLAxiom :: Ord a => (a -> String) -> LAxiom a l -> String
ppLAxiom p ax = ppLFormula p (axToFormula ax)
-- | Type of formula labels. Note that logical atoms are their own labels.
data Label a l
= L l -- ^ Regular label
| A a -- ^ Logical atom
deriving (Eq, Ord, Show)
-- | Returns the label of a labelled axiom.
axLabel :: LAxiom a l -> l
axLabel (LAx _ _ _ l) = l
-- | Returns the label of a labelled formula.
label :: LFormula k a l -> Label a l
label = foldF A (\_ _ -> L) (\_ _ _ _ -> L)
--------------------------------------------------------------------------------
-- Mapping functions
-- mapAtoms :: Ord a' => (a -> a') -> LFormula k a l -> LFormula k a' l
-- mapAtoms f (Atom a) = Atom (f a)
-- mapAtoms f (Conj a b l) = Conj (mapAtoms f a) (mapAtoms f b) l
-- mapAtoms f (Impl a e c b l) =
-- Impl (mapAtoms f a) (over pack (MS.map f) e) c (mapAtoms f b) l
mapCty :: (ReactionList a -> ReactionList a) -> LFormula k a l -> LFormula k a l
mapCty _ (Atom a) = Atom a
mapCty f (Conj f1 f2 l) = Conj (mapCty f f1) (mapCty f f2) l
mapCty f (Impl f1 eb cty f2 l) = Impl (mapCty f f1) eb (f cty) (mapCty f f2) l
-- mapCtyAx :: (cty1 -> cty2) -> LAxiom a l -> LAxiom a l
-- mapCtyAx f (LAx f1 cty f2 l) = LAx f1 (f cty) f2 l
--------------------------------------------------------------------------------
-- Deep heterogeneous comparison functions
isEq :: Ordering -> Either Ordering Ordering
isEq x = if x == EQ then Right x else Left x
-- | Returns the result of a deep heterogeneous comparison between two labelled formulas.
--
-- Comparison is "deep" in the sense that is considers the entire recursive
-- structure of formulas. This is unlike 'frmlHetOrd', which only compares
-- labels.
deepHetComp
:: (Ord a, Ord l)
=> LFormula k1 a l -> LFormula k2 a l -> Ordering
deepHetComp (Atom x1) (Atom x2) = compare x1 x2
deepHetComp (Atom _) _ = LT
deepHetComp (Conj a1 b1 l1) (Conj a2 b2 l2) =
either id id $ isEq ca >> isEq cb >> pure cl
where ca = deepHetComp a1 a2 ; cb = deepHetComp b1 b2 ; cl = compare l1 l2
deepHetComp Conj{} (Atom _) = GT
deepHetComp Conj{} Impl{} = LT
deepHetComp (Impl a1 eb1 cs1 b1 l1) (Impl a2 eb2 cs2 b2 l2) =
either id id $ isEq ca >> isEq cb >> isEq ceb >> isEq ccs >> pure cl
where
ca = deepHetComp a1 a2 ; cb = deepHetComp b1 b2 ; ceb = compare eb1 eb2
ccs = compare cs1 cs2 ; cl = compare l1 l2
deepHetComp Impl{} _ = GT
--------------------------------------------------------------------------------
-- -- | Type of labelled formulas to be used during proof search.
-- newtype SrchFormula a l k = Srch { unSrch :: LFormula k a l }
-- instance (Show a, Show l) => Show1 (SrchFormula a l) where
-- show1 (Srch f) = show f
-- instance (Ord a, Ord l) => HEq (SrchFormula cty a l) where
-- hetCompare (Srch f1) (Srch f2) = compare (label f1) (label f2)
instance Eq l => Eq (LAxiom a l) where
ax1 == ax2 = axLabel ax1 == axLabel ax2
instance Ord l => Ord (LAxiom a l) where
compare ax1 ax2 = compare (axLabel ax1) (axLabel ax2)
-- type instance Atom (SrchFormula cty a l) = a
-- type instance Eb (SrchFormula cty a l) = ElemBase a
-- type instance Ax (SrchFormula cty a l) = LAxiom cty a l
-- sfrmlView :: SrchFormula cty a l k
-- -> FrmlView (SrchFormula cty a l) k (ElemBase a) cty a
-- sfrmlView (Srch (Atom a)) = AtomRepr a
-- sfrmlView (Srch (Conj f1 f2 _)) = ConjRepr (Srch f1) (Srch f2)
-- sfrmlView (Srch (Impl f1 e c f2 _)) = ImplRepr (Srch f1) e c (Srch f2)
-- decideN :: Neutral (SrchFormula cty a l) -> Maybe (BFormula a l)
-- decideN = switchN (\(Srch (Atom x)) -> Just (BAtom x)) (const Nothing)
-- decideOF :: Opaque (SrchFormula cty a l) -> Maybe (BFormula a l)
-- decideOF (O (Srch f)) = decideF f