简化功能输出不完全符合预期

时间:2018-09-27 01:46:13

标签: clojure expression simplify

我正在尝试编写一个函数,该函数将简化布尔表达式的任意列表,但是我的函数无法通过某些测试。

  (defn sim
  [expression]
  (if (some true? expression)
    true
    (if (= (count expression) 2)
      (if (some false? expression)
        false
        (if (map simple-symbol? expression)
          (if (= (count expression) 2)
            (drop 1 expression)
            expression)))
      (if (some simple-symbol? (drop 1 expression))
        (filter simple-symbol? expression)))))

当我使用(sim '(or x false))进行呼叫时,我期望输出为(x),但是它将返回(or x)。相反,当我使用(sim '(or x))进行呼叫时,我的输出是预期的(x)

3 个答案:

答案 0 :(得分:1)

这些方面的情况如何?这仅适用于or,但是我敢肯定我们可以对and和其他布尔运算符执行相同的操作。

(defn simplify-or [exp]
  (let [op (first exp)
        args (rest exp)]
    (when (= op 'or)
      (let [nf-args (filter #(symbol? %) args)]
        (if (some true? args)
          true
          (case (count nf-args)
            0 false
            1 (first nf-args)
            (concat (list op) nf-args)))))))

结果:

(simplify-or '(or false))       
=> false

(simplify-or '(or true))       
=> true

(simplify-or '(or x true y false))       
=> true

(simplify-or '(or x y false))       
=> (or x y)

答案 1 :(得分:0)

(defn simplify-or
  [[op & args]]
  (let [args-without-false (remove false? args)]
    (cond
      (some true? args-without-false) true
      (= 1 (count args-without-false)) args-without-false
      (empty? args-without-false) false
      :otherwise (conj args-without-false op))))

(simplify-or '(or x false y))
#=> (or x y)
(simplify-or '(or x))
#=> (x)
(simplify-or '(or x true y false))
#=> true
(simplify-or '(or false false)
#=> false

我的担心是这里有些矛盾,(x)是什么?为什么不只是x?与我们只返回truefalse的方式相同。

答案 2 :(得分:0)

(require '[clojure.walk :as w])

(defmulti dispatch first)

(defmethod dispatch 'or
    [[op & args]]
    (if (contains? (into #{} args) true)
        true
        (case (count (remove false? args))
            0 false
            1 (first (remove false? args))
            (cons op (remove false? args)))))

(defmethod dispatch 'and
    [[op & args]]
    (if (contains? (into #{} args) false)
        false
        (case (count (remove true? args))
            0 false
            1 (first (remove true? args))
            (cons op (remove true? args)))))

(defmethod dispatch :default [x] x)

(defn simplify [x]
    (prn (w/postwalk (fn [x]
                         (if (and (list? x) (seq x))
                             (dispatch x)
                             x))
                     x)))

(simplify '(or x false))
(simplify '(or x (or y false) z false))
(simplify '(or x (or y false) (and z false)))
(simplify '(or x false y))
(simplify '(or x))
(simplify '(or x (or x true y false)))
(simplify '(or false false (and true true)))