haskellmodal-logic

Extending propositional logic to modal logic in Haskell


I have written some code in Haskell for modeling propositional logic

data Formula = Prop {propName :: String} 
            | Neg Formula 
            | Conj Formula Formula 
            | Disj Formula Formula
            | Impl Formula Formula 
            | BiImpl Formula Formula 
    deriving (Eq,Ord)

However, there is no natural way to extend this to Modal Logic, since the data type is closed. Therefore, I thought I should use classes instead. That way, I can easily add new language features in different modules later on. The problem is that I don't exactly know how to write it. I would like something like the following

type PropValue = (String,Bool) -- for example ("p",True) states that proposition p is true
type Valuation = [PropValue]    

class Formula a where
    evaluate :: a -> Valuation -> Bool

data Proposition = Prop String

instance Formula Proposition where
    evaluate (Prop s) val = (s,True) `elem` val 

data Conjunction = Conj Formula Formula -- illegal syntax

instance Formula Conjunction where
    evaluate (Conj φ ψ) v = evaluate φ v && evaluate ψ v

The mistake is of course in the definition of Conjunction. However, it is unclear to me how I could rewrite it so that it works.


Solution

  • This should work:

    data Conjunction f = Conj f f
    
    instance Formula f => Formula (Conjunction f) where
        evaluate (Conj φ ψ) v = evaluate φ v && evaluate ψ v
    

    However, I am not sure type classes are the right tool for what you are trying to achieve.


    Maybe you could give a whirl to using explicit type level functors and recurring over them:

    -- functor for plain formulae
    data FormulaF f = Prop {propName :: String} 
                | Neg f
                | Conj f f
                | Disj f f
                | Impl f f
                | BiImpl f f
    
    -- plain formula
    newtype Formula = F {unF :: FormulaF Formula}
    
    -- functor adding a modality
    data ModalF f = Plain f
                 | MyModality f
    -- modal formula
    newtype Modal = M {unM :: ModalF Modal}
    

    Yes, this is not terribly convenient since constructors such as F,M,Plain get sometimes in the way. But, unlike type classes, you can use pattern matching here.


    As another option, use a GADT:

    data Plain
    data Mod
    data Formula t where
       Prop {propName :: String} :: Formula t
       Neg  :: Formula t -> Formula t
       Conj :: Formula t -> Formula t -> Formula t
       Disj :: Formula t -> Formula t -> Formula t
       Impl :: Formula t -> Formula t -> Formula t
       BiImpl :: Formula t -> Formula t -> Formula t
       MyModality :: Formula Mod -> Formula Mod 
    
    type PlainFormula = Formula Plain
    type ModalFormula = Formula Mod