Консолидированные аргументы cond в Clojure (стиль CL) - PullRequest
2 голосов
/ 09 ноября 2010

В Clojure я делаю это

(println (cond false "don't care" "otherwise" "otherwise"))

В Common LISP это будет

(print (cond (nil "don't care") ("otherwise") ))

Есть ли способ получить такой упрощенный cond в Clojure?

Ответы [ 2 ]

1 голос
/ 09 ноября 2010

Версия, которая включает исправление для этого Алекса Таггарта, замеченное ниже. Проходит все тестовые случаи, показанные в тесте. Это позволяет произвольным предложениям, переданным в my-cond, иметь длину 1 вместо 2, что приводит к тому, что предложение длины 1 является одновременно и тестом на достоверность, и результатом, если оно истинно. Исходя из моего ограниченного опыта работы с CL, я на самом деле думаю, что это поведение отличается от того, что делает cond, но, похоже, соответствует тому, как я интерпретировал то, что вы просите. Кажется, что ответ Kotarak совпадает с ответом CL, поскольку использование последнего оператора в CL cond, похоже, совпадает с использованием предложения :else в версии Clojure.

Несмотря на это, здесь есть решение, в котором любое предложение должно иметь длину, равную единице, и использовать его как для проверки на истинность, так и для результата.

(defmacro my-cond
  [& others]
  (if others
    (let [more# (next others)
          extra-clauses# (if more# `(my-cond ~@more#))
          clause# (first others)]
      (if (= 2 (count clause#))
        `(if ~(first clause#) ~(second clause#) ~extra-clauses#)
        `(if ~(first clause#) ~(first clause#)  ~extra-clauses#)))))


(deftest my-cond-works
  (is (= 3 (my-cond (false 1) (false 2) (3))))
  (is (= "otherwise" (my-cond (false "don't care") ("otherwise"))))
  (is (= nil (my-cond (:one nil) ("otherwise"))))
  (is (= "care" (my-cond (1 "care") ("otherwise"))))
  (is (= "otherwise" (my-cond (false "care") ("otherwise") (true "true"))))
  (is (= "silly" (my-cond (nil "no") (nil) ("yes" "silly")))))

Я бы действительно посоветовал перевести CL в форму Clojure cond. Я бы возложил ментальные накладные расходы на использование синтаксиса CL вместе с синтаксисом Clojure в одном проекте, так как не стоит экономить время на его переводе сейчас. Глядя на код в будущем после того, как вы привыкли к тому, как Clojure cond, и пытаясь вспомнить, почему существует другой синтаксис, кажется, не стоит времени, сэкономленного без перевода.

Ниже версия терпит неудачу, как говорит Алекс Таггарт ниже. Хранение здесь, чтобы его комментарий имел смысл. Следующая версия делает:

(defmacro my-cond [[if1 then1] & others]
  (when (or if1 then1 others)
    (let [extra-clauses# (if others `(my-cond ~@others))]
      (if then1
        `(if ~if1 ~then1 ~extra-clauses#)
        `(if ~if1 ~if1  ~extra-clauses#)))))

user> (my-cond (false "first") (nil nil) ("otherwise"))
"otherwise"
0 голосов
/ 09 ноября 2010

Я полагаю, что версия clojure должна была иметь меньше паренов. Вы, конечно, можете написать свой собственный макрос cond-ish, чтобы делать то, что вы хотите.

Вот простая реализация (т.е. не реализована полная версия CL) ...

(defmacro my-cond [[if1 then1] & others]
  (if others 
    `(if ~if1 ~then1 (my-cond ~@others))
    `(if ~if1 ~then1)))

И тогда вы можете ...

(my-cond (false 1) (false 2) (3 3))   ; results in 3
...