Cleaner Alternative to Extensive Pattern Matching in Haskell

后端 未结 5 1257
旧巷少年郎
旧巷少年郎 2021-02-07 01:13

Right now, I have some code that essentially works like this:

data Expression 
    = Literal Bool 
    | Variable String
    | Not Expression 
    | Or Expressio         


        
5条回答
  •  [愿得一人]
    2021-02-07 01:49

    You could write a generic simplifier for all binary operations:

    simplifyBinWith :: (Bool -> Bool -> Bool) -- the boolean operation
                    -> (Expression -> Expression -> Expression) -- the constructor
                    -> Expression -> Expression -- the two operands
                    -> Expression) -- the simplified result
    simplifyBinWith op cons a b = case (simplify a, simplify b) of
        (Literal x, Literal y) -> Literal (op x y)
        (Literal x, b')        -> tryAll (x `op`) b'
        (a',        Literal y) -> tryAll (`op` y) a'
        (a',        b')        -> cons a' b'
      where
        tryAll f term = case (f True, f False) of -- what would f do if term was true of false
          (True,  True)  -> Literal True
          (True,  False) -> term
          (False, True)  -> Not term
          (False, False) -> Literal False
    

    That way, your simplify function would become

    simplify :: Expression -> Expression
    simplify (Not e)   = case simplify e of
        (Literal b) -> Literal (not b)
        e'          -> Not e'
    simplify (And a b) = simplifyBinWith (&&) And a b
    simplify (Or a b)  = simplifyBinWith (||) Or a b
    simplify t         = t
    

    and could be easily extended to more binary operations. It would also work well with the Binary Op Expression Expression idea, you'd pass Op instead of an Expression constructor to simplifyBinWith and the pattern in simplify could be generalised:

    simplify :: Expression -> Expression
    simplify (Not e)         = case simplify e of
        (Literal b) -> Literal (not b)
        e'          -> Not e'
    simplify (Binary op a b) = simplifyBinWith (case op of
        And -> (&&)
        Or -> (||)
        Xor -> (/=)
        Implies -> (<=)
        Equals -> (==)
        …
      ) op a b
    simplify t               = t
      where
        simplifyBinWith f op a b = case (simplify a, simplify b) of
          (Literal x, Literal y) -> Literal (f x y)
          …
          (a',        b')        -> Binary op a' b'
    

提交回复
热议问题