我正在处理以下语法,该语法已以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)
感觉就像是对问题的不完美解决方案,因为它不断重复运行感觉(如果定义正确)仅需要运行一次的功能。感谢您的反馈。
答案 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
...