Упрощение вывода функции не совсем так, как ожидалось - PullRequest
0 голосов
/ 27 сентября 2018

Я пытаюсь написать функцию, которая упростит произвольный список логических выражений, но моя функция не проходит определенные тесты.

  (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 голосов
/ 27 сентября 2018
(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?Так же, как мы возвращаем только true или false.

0 голосов
/ 27 сентября 2018
(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)))
0 голосов
/ 27 сентября 2018

Как насчет чего-то подобного?Это только для 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)
...