packages feed

lattest-lib-0.1.0.0: test/Reference/FreeLatticeSlow.hs

{-# LANGUAGE StandaloneDeriving #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE DeriveFunctor #-}
{-# LANGUAGE DeriveFoldable #-}
module Reference.FreeLatticeSlow (
FreeLatticeSlow,
)

where

import qualified Lattest.Model.Symbolic.Expr as E


import Algebra.Lattice.Free (Free(..), lowerFree)
import Algebra.Lattice.Levitated(Levitated(..))
import Algebra.Lattice(Lattice)
import qualified Algebra.Lattice as L ((/\), (\/))
import Control.Monad(ap)
import Lattest.Model.BoundedMonad (BoundedConfiguration (..), JoinSemiLattice (..), MeetSemiLattice (..), BooleanConfiguration (..))


{-|
    Free distributive lattice, or a positive boolean formula, i.e., a boolean formula with conjunctions and disjunctions over atomic propositions. The two elements 'top' and 'bot' can be interpreted as true and false.
    Behaviourally, this is equivalent to `FreeLattice`, but the size is not bounded by the normal form.
    This makes it less efficient when repeatedly applying operators, especially 'fmap' and monadic bind '>>='.
-}
newtype FreeLatticeSlow a = FreeLatticeSlow (Levitated (Free a)) deriving (Eq, Functor, Foldable, Lattice)

deriving instance Ord a => Ord (FreeLatticeSlow a)
deriving instance Ord a => Ord (Free a)

{-
-- Conjunction and disjunction on free distributive lattices.
-- note: this is already imlpemented by the JoinSemiLattice instance
(\/) :: FreeLatticeSlow a -> FreeLatticeSlow a -> FreeLatticeSlow a
(\/) = (L.\/)

-- | Conjunction on free distributive lattices.
(/\) :: FreeLatticeSlow a -> FreeLatticeSlow a -> FreeLatticeSlow a
(/\) = (L./\)
-}

{-|
    An FreeLatticeSlow as a state configuration means an automaton is in a state configuration of disjunctions (non-determinism) and conjunctions over states,
    where state configurations top and bottom, or true and false, indicate underspecified and forbidden configurations, respectively.
-}
instance BoundedConfiguration FreeLatticeSlow where
    isForbidden (FreeLatticeSlow Bottom) = True
    isForbidden _ = False
    isUnderspecified (FreeLatticeSlow Top) = True
    isUnderspecified _ = False
    forbidden = FreeLatticeSlow Bottom
    underspecified = FreeLatticeSlow Top

instance Applicative FreeLatticeSlow where
    pure = FreeLatticeSlow . Levitate . Var
    (<*>) = ap

instance Monad FreeLatticeSlow where
    (FreeLatticeSlow Bottom) >>= _ = FreeLatticeSlow Bottom
    (FreeLatticeSlow Top) >>= _ = FreeLatticeSlow Top
    (FreeLatticeSlow (Levitate x)) >>= f = lowerFree f x

instance Show a => Show (FreeLatticeSlow a) where
    show (FreeLatticeSlow Top) = "⊤"
    show (FreeLatticeSlow Bottom) = "⊥"
    show (FreeLatticeSlow (Levitate a)) = show' a
        where
        show' (Var a') = show a'
        show' (x :\/: y) = "(" ++ show' x ++ " ∨ " ++ show' y ++ ")"
        show' (x :/\: y) = "(" ++ show' x ++ " ∧ " ++ show' y ++ ")"

instance JoinSemiLattice (FreeLatticeSlow a) where
    (\/) = (L.\/) -- it should be possible to generalize this to arbitrary instances, see remark below the JoinSemiLattice class itself

instance MeetSemiLattice (FreeLatticeSlow a) where
    (/\) = (L./\) -- it should be possible to generalize this to arbitrary instances, see remark below the JoinSemiLattice class itself

instance BooleanConfiguration FreeLatticeSlow where
    asExpr (FreeLatticeSlow Top) = E.sTrue
    asExpr (FreeLatticeSlow Bottom) = E.sFalse
    asExpr (FreeLatticeSlow (Levitate a)) = asExpr' a
        where
        asExpr' (Var a') = a'
        asExpr' (x :\/: y) = asExpr' x E..|| asExpr' y
        asExpr' (x :/\: y) = asExpr' x E..&& asExpr' y

instance Traversable FreeLatticeSlow where
  sequenceA (FreeLatticeSlow Bottom)       = pure $ FreeLatticeSlow Bottom
  sequenceA (FreeLatticeSlow Top)          = pure $ FreeLatticeSlow Top
  sequenceA (FreeLatticeSlow (Levitate a)) = FreeLatticeSlow . Levitate <$> sequenceA a