如何实现逻辑语句的同时替换?解决分步替换覆盖问题
逻辑语句同时替换的实现方案
问题描述
需要实现逻辑语句的符号替换功能,通过映射{B=¬(C), C=B}将语句(B → (C → B))转换为(¬(C) → (B → ¬(C)))。但采用分步替换(先替换B,再替换C)会导致已替换的内容被二次修改,输出错误结果(¬(B) → (B → ¬(B)))。
解决方案
核心思路是基于原始AST节点进行一次性替换,遍历每个节点时直接查询映射表完成替换,避免分步替换带来的干扰。修改各类的subs方法,使其接受一个字典类型的映射参数,而非单个目标-替换对。
修改后的完整代码
from dataclasses import dataclass @dataclass(frozen=True) class Symb: pass @dataclass(frozen=True) class PrimConn(Symb): pass @dataclass(frozen=True) class Not(PrimConn): arg: Symb def __repr__(self): return f"¬({self.arg})" def subs(self, mapping: dict): # 递归处理子节点的替换 return Not(self.arg.subs(mapping)) @dataclass(frozen=True) class To(PrimConn): arg1: Symb arg2: Symb def __repr__(self): return f"({self.arg1} → {self.arg2})" def subs(self, mapping: dict): # 递归处理两个子节点的替换 return To( self.arg1.subs(mapping), self.arg2.subs(mapping) ) @dataclass(frozen=True) class StatLett(Symb): name: str def __repr__(self): return self.name def subs(self, mapping: dict): # 若当前符号在映射中,返回替换值;否则返回自身 return mapping.get(self, self) def main(): b = StatLett("B") c = StatLett("C") prop = To(b, To(c, b)) print(prop) # 输出: (B → (C → B)) # 传入完整映射进行一次性替换 prop = prop.subs({b: Not(c), c: b}) print(prop) # 输出: (¬(C) → (B → ¬(C))) if __name__ == "__main__": main()
关键说明
- StatLett.subs:直接检查当前符号是否在映射字典中,存在则返回对应的替换节点,否则返回自身。这保证了每个原始符号只被替换一次。
- Not/To.subs:递归调用子节点的
subs方法,确保整个AST树的所有节点都能被正确处理。 - 一次性映射传入:通过
{b: Not(c), c: b}将所有替换规则一次性传入,遍历AST时基于原始节点进行替换,避免分步替换导致的二次修改。
内容的提问来源于stack exchange,提问作者Jasper
相关产品推荐
相关产品推荐

