Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/jquery-ui/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
“定义”的好处是什么;或;clojure中的操作是作为宏而不是简单的函数?_Clojure - Fatal编程技术网

“定义”的好处是什么;或;clojure中的操作是作为宏而不是简单的函数?

“定义”的好处是什么;或;clojure中的操作是作为宏而不是简单的函数?,clojure,Clojure,我希望这个解释能让我更好地了解使用宏的好处。在函数中,所有参数都是在调用之前计算的 这意味着作为函数的或不能是惰性的,而宏可以将或重写为if语句,该语句仅在必要时对分支求值 更具体地说,考虑一下: (or (cached-lookup) (expensive-operation)) …它被改写成什么样子: (let [or__1234__auto (cached-lookup)] (if or__1234__auto or__1234__auto (expensive-o

我希望这个解释能让我更好地了解使用宏的好处。

在函数中,所有参数都是在调用之前计算的

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


更具体地说,考虑一下:

(or (cached-lookup) (expensive-operation))
…它被改写成什么样子:

(let [or__1234__auto (cached-lookup)]
  (if or__1234__auto
    or__1234__auto
    (expensive-operation)))
…这样,如果
(缓存查找)
的返回值为
nil
false
,我们只对
(昂贵的操作)
进行评估。在实现常规JVM调用约定时,您无法使用函数实现这一点:
昂贵的操作将始终进行求值,无论是否需要其结果,以便将其结果作为参数传递给函数


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

(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
)以宏无法实现的方式包装、修改或调用函数。

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

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

如果你猜到它永远不会终止,你是对的!事实上,它们都是扩展到
if
的宏。宏允许我们在运行之前将代码翻译成其他代码,这样宏就没有访问值的权限,只有代码

旁白:宏俱乐部的第一条规则是不要写宏。这就是说:在某些情况下,宏是绝对必要的(
core.async
不可能是一个库,而不是一个没有宏的核心语言功能),但是如果你不在这些情况下,最好避免使用宏。除非
l
是无止境的,否则宏将终止。@Thumbnail不,事实上它不是,因为它无条件地递归调用
some
。看起来它终止是因为你习惯了
短路,但这个答案的重点是演示一个案例,说明短路很重要:如果他们没有短路,这个函数永远不会终止@阿玛洛伊啊!对。