{-# 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
, LFormula(..)
, ppLFormula
, elemBase
, label
, frmlHetEq
, frmlHetOrd
, deepHetComp
, LAxiom(..)
, axLabel
, axToFormula
, ppLAxiom
, Opaque(..)
, withOpaque
, oConj
, oImpl
, 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)
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)
frmlHetEq :: (Eq a, Eq l) => LFormula k1 a l -> LFormula k2 a l -> Bool
frmlHetEq f1 f2 = label f1 == label f2
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)
ppLFormula :: (a -> String) -> LFormula k a l -> String
ppLFormula p = foldF p (\a b _ -> fold [a, " ⊗ ", b])
(\a _ _ b _ -> fold ["(", a, " → ", b, ")"])
elemBase :: Ord a => LFormula k a l -> ElemBase a
elemBase = foldF (ElemBase . singleton) (\a b _ -> a <> b) (\_ e _ _ _ -> e)
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
oConj :: Opaque a l -> Opaque a l -> l -> LFormula KConj a l
oConj (O f1) (O f2) = Conj f1 f2
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
data BFormula a l = BAtom a | BConj (BFormula a l) (BFormula a l) l
deriving (Functor, Foldable, Traversable, Show)
bAtom :: a -> BFormula a l
bAtom = BAtom
bConj :: l -> BFormula a l -> BFormula a l -> BFormula a l
bConj l f1 f2 = BConj f1 f2 l
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)
bfToAtoms :: BFormula a l -> NonEmpty a
bfToAtoms (BAtom bf) = bf :| []
bfToAtoms (BConj f1 f2 _) = bfToAtoms f1 <> bfToAtoms f2
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
data LAxiom a l = LAx (BFormula a l) (ReactionList a) (BFormula a l) l
deriving (Show, Functor, Foldable, Traversable)
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
ppLAxiom :: Ord a => (a -> String) -> LAxiom a l -> String
ppLAxiom p ax = ppLFormula p (axToFormula ax)
data Label a l
= L l
| A a
deriving (Eq, Ord, Show)
axLabel :: LAxiom a l -> l
axLabel (LAx _ _ _ l) = l
label :: LFormula k a l -> Label a l
label = foldF A (\_ _ -> L) (\_ _ _ _ -> 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
isEq :: Ordering -> Either Ordering Ordering
isEq x = if x == EQ then Right x else Left x
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
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)