简化布尔表达式的函数

时间:2018-12-03 19:52:55

标签: haskell functional-programming boolean

我正在处理以下语法,该语法已以Haskell data类型的形式实现。

    bool ::=   tt   |   ff   |   bool ∧ bool   |   var        
    var  ::=   letter{letter|digit}*

我的问题是,我想编写一个函数simplify :: bool → bool,该函数以通常的方式简化布尔表达式(而对变量不执行任何操作)。例如,我想要

    simplify(tt ∧ ff) = ff
    simplify(tt ∧ x) =  x
    simplify(x ∧ (y ∧ z)) = x ∧ y ∧ z

其中字母 x y z 表示变量(var)。

我认为自然定义如下(具有模式匹配的伪代码)

    simplify(tt) = tt
    simplify(ff) = ff
    simplify(x)  = x
    simplify(tt ∧ b) = simplify(b)
    simplify(b ∧ tt) = simplify(b)
    simplify(b₁ ∧ b₂) = simplify(b₁) ∧ simplify(b₂)                (†)

其中 b b₁ b_2 分别表示 bool x 表示 var

该定义适用于上面所有给定的示例。问题出在诸如(tt ∧ tt) ∧ (tt ∧ tt)之类的表达式上。确实,应用定义,我们有

    simplify((tt ∧ tt) ∧ (tt ∧ tt)) = simplify(tt ∧ tt) ∧ simplify(tt ∧ tt) 
                                    = simplify(tt) ∧ simplify(tt) 
                                    = tt ∧ tt

,我们应该能够进一步简化为tt

因此可能将定义行(†)更改为

    simplify(b₁ ∧ b₂) = simplify(simplify(b₁) ∧ simplify(b₂))

将解决该问题,因为它简化了连接的结果,这实际上是可行的!但是,当我们有了变量时,它就中断了(实际上它进入了无限循环):

    simplify(x ∧ y) = simplify(simplify(x) ∧ simplify(y))   
                    = simplify(x ∧ y)       
                    = ...

因此,我的想法是保留旧的定义,但实际上通过查找固定点来简化。确实,下面用Haskell编写的函数simplify' :: bool → bool的作用如预期:

simplify' :: BoolExpr -> BoolExpr
simplify' f 
    | (simplify f) == f   = f
    | otherwise           = simplify' (simplify f)

感觉就像是对问题的不完美解决方案,因为它不断重复运行感觉(如果定义正确)仅需要运行一次的功能。感谢您的反馈。

2 个答案:

答案 0 :(得分:3)

simplify(b₁ ∧ b₂) = simplify(simplify(b₁) ∧ simplify(b₂))
     

将解决该问题,因为它简化了连接的结果,这实际上是可行的!但是,当我们有了变量时,它就中断了(实际上它进入了无限循环):

您真的要递归simplify(b₁) ∧ simplify(b₂)吗?也许您想simplify(b₁)simplify(b₂)然后简单地操作它们。如

data B = T | F | V | B :&: B deriving Show

s :: B -> B
s T = T
s F = F
s V = V
s (b1 :&: b2) = opAND (s b1) (s b2) 

opAND F _ = F
opAND _ F = F 
opAND T b = b
opAND b T = b
opAND a b = a :&: b

简化函数s本质上是折叠您的语法树,在每一步都保证您保留简化表达式是原子的或不包含F或{{1}都不出现的属性}。

答案 1 :(得分:1)

基本问题是您要对未简化的表达式进行simplify(tt ∧ b)测试。

您要寻找的逻辑更像是:

simplify(a ^ b) | simplify(a) == tt = simplify b

,可以通过简化简化模式匹配之前的 有效地实现:

simplify(b₁ ∧ b₂) =
  case (simplify(b₁), simplify(b₂)) of
    (tt, x) -> x
    (x, tt) -> x
    ...