定义"或"有什么好处?在clojure中作为一个宏而不是简单地作为一个函数运行?

时间:2017-01-24 00:35:05

标签: clojure

我希望这些解释能让我更好地了解使用宏的优势。

2 个答案:

答案 0 :(得分:8)

在函数中,所有参数在调用之前都会被计算。

这意味着or作为一个函数不能是惰性的,而宏可以将or重写为if语句,该语句仅在需要时对分支进行求值

更具体地说,考虑一下:

(or (cached-lookup) (expensive-operation))

......它被重写成以下内容:

(let [or__1234__auto (cached-lookup)]
  (if or__1234__auto
    or__1234__auto
    (expensive-operation)))

...因此,如果(expensive-operation)的返回值为(cached-lookup)nil,我们仅评估false。在实现常规JVM调用约定时,您无法使用函数执行此操作:expensive-operation始终进行评估,无论是否需要其结果,以便可以传递其结果作为函数的一个参数。

顺便提一下,如果你将零参数函数作为参数,那么可以在这种情况下实现一个函数。也就是说,你可以这样做:

(defn or*
  ([] false)                                                ; 0-arg case
  ([func-one] (func-one))                                   ; 1-arg case
  ([func-one func-two]                                      ; optimized two-arg case
   (let [first-result (func-one)]
     (if first-result
       first-result
       (func-two))))
  ([func-one func-two & rest]                               ; general case
   (let [first-result (func-one)]
     (if first-result
       first-result
       (apply or* func-two rest)))))

当你必须实现一个宏时,让它生成" thunks" (匿名函数),并将它们传递给更高阶的函数,例如;这实际上有助于可组合性,因为函数可以使用更高级别的函数进行包装,修改或调用,例如partial以宏不能的方式。

答案 1 :(得分:0)

猜猜在这种情况下如果orand是函数会发生什么?

(defn some [f l]
  (and (seq l)
       (or (f (first l)) 
           (some f (rest l))))) 

如果你猜对它永远不会终止你是对的!事实上,它们都是扩展到if的宏。宏允许我们在运行之前将代码转换为其他代码,这样宏就无法访问值,只需访问代码。