按位运算符递归

Recursion with bitwise operators

我在 java 中有以下使用递归简化 Nor expressions 的方法:

public Expression simplify() {
        // x ↓ T = F
        if (this.getRight().toString().equals("T")) {
            return new Val(false).simplify();
        }
        // T ↓ x = F
        if (this.getLeft().toString().equals("T")) {
            return new Val(false).simplify();
        }
        // x ↓ F = ~(x)
        if (this.getRight().toString().equals("F")) {
            return new Not(super.getLeft().simplify());
        }
        // F ↓ x = ~(x)
        if (this.getLeft().toString().equals("F")) {
            return new Not(super.getRight().simplify());
        }
        // x ↓ x = ~(x)
        if (this.getLeft().toString().equals(this.getRight().toString())) {
            return new Not(this.getRight().simplify());
        }
        return new Nor(this.getLeft().simplify(), this.getRight().simplify());
    }  

现在,当我想简化表达式 (T ↓ y) ↓ y 时,它会输出 F ↓ y 而不是 ~(y).
我需要如何更改递归以输出正确的简化表达式?

你的情况没有被涵盖,所以你得到默认值,一直到最后:简化左边,简化右边,然后 return 那。

问题是,您简化了左侧节点,将 (T ↓ y) 变为 F,右侧节点(没有变化),但是您无法继续应用简化:您只是 return lhs ↓ rhs, 不简化这个.

一个非常简单的调试运行应该已经找到了,不是吗?也许下次尝试阅读您的代码并在达到 SO 之前多逐步执行它。

就其价值而言,我将在此处进行 2 项重大改进:

我会从里到外工作,这几乎从定义上讲更聪明,因为您的简化规则都只适用于非复杂节点。

因此,我会采用您的左右节点,首先简化它们,然后 运行 您的简化规则。这样就无需简化最终结果。

因此,不要在一百万个地方传递 super.getRight(),而是从:

开始
Node left = getLeft().simplify();
Node right = getRight().simplify();

然后检查你的规则,这次只使用左和右(与 super.getLeft().simplify() 相比)。如果你的规则中的 none 适用,则进一步的简化不会帮助你,所以你可以 return new Nor(left, right),然后就可以完成了。

第二个主要更新:toString() 是一个调试/日志工具 - 与 toString 相比,对业务逻辑进行编程必然会破坏行为,即使它不是直接错误。因此,通过 getLeft().toString().equals("T") 检查 'is the left node the node representing a constant TRUE value' 是糟糕的代码风格,并且会自找麻烦。

应该有一个正确的方法来检查这个。可能是 if (left.isConstantTrue()) 或者 if (left.equals(Node.TRUE)),或者可能是 if (left instanceof Constant c && c.value)(这是 JDK16 语法,没有 JDK16 就很啰嗦:if ((left instanceof Constant) && ((Constant) left).value).

None 其中依赖于调试辅助代码永远不会更改,并且任何其他节点也永远不会打印 T,并且通常将您的代码修复为惯用的,而不是一个会触发所有 linter 工具的东西。

此外,super 调用很奇怪。您有时调用 super.getRIght,有时调用 this.getRight。通常,除非有特定原因,否则不要指定 this/super。为什么要跳过 getRight 的任何本地覆盖?您可能没有/您甚至可能 没有 覆盖,这使得 super.getRight()this.getRight()getRight() 都 100% 等效。只需写 getRight() - 与您的语义意图相匹配,即 'get the Right node',而不是 'get the superclass impl of getRight, intentionally skipping past any custom modifications this instance has performed'.