Есть ли у Clojure логика короткого замыкания? - PullRequest
5 голосов
/ 19 ноября 2011

На многих языках, если вы пишете что-то вроде

if (foo() || bar() || foobar()) { /* do stuff */ }

и foo () возвращает true, тогда bar () и foobar () не будут оцениваться.

Предположим, у меня был следующий код Clojure:

(let [a (simple-function args)
      b (complex-function args)
      c (too-lazy-to-optimize-this-function args)]
  (or a b c))

Если a имеет значение true, будут ли также оцениваться значения b и c или они будут игнорироваться?

Спасибо!

Ответы [ 6 ]

12 голосов
/ 19 ноября 2011

Поскольку вы ответили на свой собственный вопрос, обратите внимание, что хотя в вашем примере b и c могут не оцениваться в вызове (или abc), привязка let оценивается до этого, поэтому слишком ленивая для оптимизации этой функциивызов оценивается в любом случае.Clojure не такой ленивый, как этот.

Для ясности: чтобы условно оценить вызовы функций, нужно поместить выражение, оценивающее их, в вызов or, в основном:

(or (simple-function args)
    (complex-function args)
    (too-lazy-to-optimize-this-function args))
11 голосов
/ 19 ноября 2011

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

user=> (or true (do (println "hello") true))
true
user=> (or false (do (println "hello") true))
hello
true
4 голосов
/ 19 ноября 2011

В случае сомнений обратитесь к документации :

или
macro
Использование:

   (or)  
   (or x)  
   (or x & next)  

Оценивает exprs по одномувремя слева направо.Если форма возвращает логическое истинное значение или возвращает это значение и не оценивает другие выражения , в противном случае возвращается значение последнего выражения.(или) возвращает ноль.

(Выделение мое.)

Документация для and показывает, что он также ведет себя аналогичным образом.

1 голос
/ 21 ноября 2011

Да, Clojure действительно имеет оценку короткого замыкания.

Одна интересная особенность Clojure / других Лиспов заключается в том, что также возможно расширить язык новыми конструкциями, которые также обеспечивают оценку короткого замыкания. Это невозможно сделать с помощью функций в большинстве других языков, так как все параметры функции должны быть оценены перед вызовом функции.

Вот пример макроса для реализации функции короткого замыкания NAND в Clojure:

(defmacro nand 
  ([x] 
    `(not ~x))              ; NAND is equivalent to NOT for one argument
  ([x & xs] 
    `(let [nand# (not ~x)]
       (if nand# 
         true               ; short circuit if we can prove the nand is true
         (nand ~@xs)))))    ; continue with the other expressions otherwise

(nand true true)
=> false

(nand false (println "Expression with a side effect!"))
=> true
1 голос
/ 19 ноября 2011

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

Из документов: "Оценивает exprs по одному, слева направо. Еслиформа возвращает логическое истинное значение или возвращает это значение и не оценивает другие выражения, в противном случае возвращается значение последнего выражения. (или) возвращает ноль. "

0 голосов
/ 19 ноября 2011
if (foo() || bar() || foobar()) { /* do stuff */ }

до

(if (or (foo) (bar) (boobar)) (comment do stuff))

или

(when (or (foo) (bar) (boobar)) (comment do stuff))
...