Clojure:使用多个参数简化逻辑表达式

时间:2017-03-07 23:42:35

标签: clojure functional-programming logic

我是Clojure的新手并试图编写一个应该简化逻辑表达式的程序。例如:

(or x false) => x
(or true x) => true
(or x y z) => (or x(or y z))

我相信,我已经想出如何简化表达式最多两个参数。但是,我不知道如何简化包含两个以上参数的表达式。我试图使用第n个函数来尝试对表达式进行分区,但这似乎使事情变得更加复杂:

(defn pre-simplify [expression n]
  (cond
    (= n 0) (nth expression 0)
    (= n 1) (nth expression 1)
    (= n 2) (nth expression 2)
    (= n 3) (nth expression 3)
   )
)

这是简化功能的代码:

(defn simplify
  ([op arg1]                                                
    (cond
      (and (= arg1 'true) (= op 'not)) false
      (and (= arg1 'false) (= op 'not)) true
      (= arg1 'true) true
      (= arg1 'false) false)
      ;not not x -> x
    )
  ([op arg1 arg2]                                         
    (cond
      (seq? arg1) (let [arg1 (simplify op arg1)]))
    (cond
      (seq? arg2) (let [arg2 (simplify op arg2)]))
    (cond
      (= op 'or) (
                 (cond
                    (and (= arg1 'false) (= arg2 'false)) false
                    (or (= arg1 'true) (= arg2 'true)) true
                    (and (= arg1 'false) (and (not= arg2 'false) (not= arg2 'true))) arg2
                    (and ((not= arg1 'false) (not= arg1 'true)) (= arg2 'false)) arg1
                )
              )
      (= op 'and') (
                   (cond
                     (and (= arg1 'true) (= arg2 'true)) true
                     (or (= arg1 'false) (= arg2 'false)) false
                     (and (= arg1 'false) (and (not= arg2 'false) (not= arg2 'true))) arg2
                     (and ((not= arg1 'false) (not= arg1 'true)) (= arg2 'false)) arg1
                   )
             )
       )
 )

另外,我想在前两个参数之后在列表的其余部分使用递归。例如,这就是我试图在两个以上的参数上进行的操作:

    ([op arg1 arg2 & rest]                                    
      (simplify op (list (op arg1 (op arg2 rest))))))  

1 个答案:

答案 0 :(得分:2)

这看起来像是家庭作业,所以让我邀请您从另一个角度考虑问题。

在Clojure中,

  • and表达式是以符号'and开头的表达式列表(或其他序列);
  • or表达式是以。开头的表达式列表 符号'or;
  • ......

表达式也可以是

  • 参数或其他本地名称的符号,或
  • 文字truefalse

simplify表达式:

  • 如果它是一个序列(使用seq?进行测试),simplify 参数(列表的所有元素,但first - rest将为您提供这些参数)。您可以使用map进行递归调用。
  • 然后,例如,如果运算符(first元素)是and符号,
    • 如果操作数中有任何false个文字(你可以使用 some要对此进行测试),请将整个表达式替换为false
    • 如果没有,remove任何true文字。

这些简化可能为其他人开辟道路。例如,

  • (and)只是true
  • (and x)只是x

无论你做什么,都要在开发时测试你的功能,确保它完成你认为的功能。在一个案例中,我被抓住了将操作员留下。我摔倒了(and x)案件。

还有什么可以帮助您确定表达式有效的方式和距离。

  • 未知运营商呢?
  • 您是否需要验证符号是否符合某些内容。如果是这样, 如何?

备注

  • 我假设我们可以忽略副作用:所有表达式都是 返回一个值。
  • 我不会用(or x y z)替换(or x (or y z))。这实现了 没有,并使用额外的令牌:与简化相反。
  • 任何Clojure值 - 数字,甚至是函数 - 都是逻辑上的 是的,falsenil除外,它们在逻辑上都是假的。是否 这与你的问题有关,我不知道。
  • 如果你感觉很聪明,你可以参考and的方式 or表示您忽略的文字(true和 分别是false),你结束的那个,以及你返回的那个 什么时候没有争论。

整个问题被认为是棘手的。如果你找到一个有效的解决方案,你将成为举世闻名的!