Закрывающие функции, которые выполняют упрощение символов c, используя 'и' - PullRequest
1 голос
/ 03 марта 2020

Я новичок в Clojure, и я изучаю, как написать программу, которая может упростить логические выражения (пока «и», чтобы выяснить, как все работает в первую очередь). Например:

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

(and-simplify '(and x true)) => x

(and-simplify '(and true false x)) => false

(and-simplify '(and x y z true)) => (and x y z)

Я уже знал, как упростить два аргумента, что все, что я могу сейчас сделать, это:

(defn and-simplify []

  (def x (and true false))
  println x)
(and-simplify)

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

(defn and-simplify [&expr]

  (def (and &expr))
)

Как правильно мне поступить?

1 Ответ

2 голосов
/ 03 марта 2020

Вот мое мнение.

(defn simplify-and
  [[op & forms]]
  (let [known-falsy?  #(or (false? %) (nil? %))
        known-truthy? #(and (not (symbol? %))
                            (not (seq? %))
                            (not (known-falsy? %)))
        falsy-forms   (filter known-falsy? forms)
        unknown-forms (remove known-truthy? forms)]
    (if (seq falsy-forms)
      (first falsy-forms)
      (case (count unknown-forms)
        0 true
        1 (first unknown-forms)
        (cons op unknown-forms)))))

(comment (simplify-and `(and true 1 2 a)))

Однако мы можем написать более обобщенный c simplify, который использует мультиметоды для упрощения списков, так что мы можем добавить больше оптимизаций без изменения существующего кода. , Вот что с оптимизацией для and, or и + из clojure.core. simplify оптимизирует только списки на основе имен, определенных в пространстве имен.

Ознакомьтесь с примерами в форме comment. Надеюсь, это имеет смысл.

(defn- known-falsy? [form]
  (or (false? form) (nil? form)))

(defn- known-truthy? [form]
  (and (not (symbol? form))
       (not (seq? form))
       (not (known-falsy? form))))

(declare simplify)

(defmulti simplify-list first)
(defmethod simplify-list :default [form] form)

(defmethod simplify-list 'clojure.core/and
  [[op & forms]]
  (let [forms         (mapv simplify forms)
        falsy-forms   (filter known-falsy? forms)
        unknown-forms (remove known-truthy? forms)]
    (if (seq falsy-forms)
      (first falsy-forms)
      (case (count unknown-forms)
        0 true
        1 (first unknown-forms)
        (cons op unknown-forms)))))

(defmethod simplify-list 'clojure.core/or
  [[op & forms]]
  (let [forms         (mapv simplify forms)
        truthy-forms  (filter known-truthy? forms)
        unknown-forms (remove known-falsy? forms)]
    (if (seq truthy-forms)
      (first truthy-forms)
      (case (count unknown-forms)
        0 nil
        1 (first unknown-forms)
        (cons op unknown-forms)))))

(defmethod simplify-list 'clojure.core/+
  [[op & forms]]
  (let [{nums true non-nums false} (group-by number? (mapv simplify forms))
        sum (apply + nums)]
    (if (seq non-nums)
      (cons op (cons sum non-nums))
      sum)))

(defn simplify
  "takes a Clojure form with resolved symbols and performs
   peephole optimisations on it"
  [form]
  (cond (set? form)    (into #{} (map simplify) form)
        (vector? form) (mapv simplify form)
        (map? form)    (reduce-kv (fn [m k v] (assoc m (simplify k) (simplify v)))
                                  {} form)
        (seq? form)    (simplify-list form)
        :else          form))

(comment
 (simplify `(+ 1 2))
 (simplify `(foo 1 2))
 (simplify `(and true (+ 1 2 3 4 5 foo)))
 (simplify `(or false x))
 (simplify `(or false x nil y))
 (simplify `(or false x (and y nil z) (+ 1 2)))
)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...