【问题标题】:Clojure: Simplifying Logical Expressions Using Several ArgumentsClojure:使用多个参数简化逻辑表达式
【发布时间】:2017-03-07 23:42:35
【问题描述】:

我是 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))))))  

【问题讨论】:

  • 连续 3 个 conds 应该做什么?我可能累了,但前 2 个应该对任何事情产生 0 影响。您正在创建 arg1 和 arg2 的本地阴影,然后将其丢弃。
  • 你是不是偶然从命令式编程中走出来的?

标签: clojure functional-programming logic


【解决方案1】:

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

在 Clojure 中,

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

表达式也可以是

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

给simplify一个表达式:

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

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

  • (and) 只是 true 和
  • (and x) 就是 x。

无论您做什么,在开发时测试您的功能,确保它按照您的想法执行。在一种情况下,我被抓到忽略了操作员。我摔倒了(and x) 案子。

还有待讨论的是,您应该如何以及在多大程度上验证表达式是否有效。

  • 未知运营商呢?
  • 您是否需要验证符号是否指代某物。如果是这样的话, 怎么样?

注意事项

  • 我假设我们可以忽略副作用:表达式所做的只是 返回一个值。
  • 我不会用(or x (or y z)) 替换(or x y z)。这达到 什么都没有,并使用额外的标记:与简化相反。
  • 任何 Clojure 值 - 一个数字,甚至是一个函数 - 都按逻辑行事 真,除了false 和nil,它们在逻辑上表现为假。无论 这与你的问题有关,我不知道。
  • 如果你觉得自己很聪明,你可以参数化and 和 or 根据您忽略的文字(true 和 false 分别),你结束的那个,你返回的那个 当没有参数时。

整个问题被认为是棘手的。如果您找到有效的解决方案,您将享誉世界!

【讨论】:

    猜你喜欢
    • 2011-11-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-02-25
    相关资源
    最近更新 更多