首页 文章

Clojure宏用于基准表达

提问于
浏览
0

我是Clojure的新手,在创建宏时遇到了一些麻烦 .

Clojure中的代码,用于评估前1,000,000个整数的总和:

(apply + (range 1E6))

此基准代码评估总和,但也打印此代码所需的纳秒数:

(let [start (System/nanoTime)
      result (apply + (range 1E6))]
      end (System/nanoTime)]
  (println "Took:" (- end start) "ns")
  result)

我将如何以下列形式与s.t.创建一个宏 . (benchmark expr)的值是expr的评估它打印以纳秒为单位评估expr所需的时间?

(defmacro benchmark [code]
  ...)

另外,关于宏如何工作,我有点困惑 . 为什么我们不能以下列形式使用普通函数?

(defn benchmark [code]
  ...)

2 回答

  • 1

    在您的情况下,宏和普通函数之间的主要区别在于参数评估顺序 . 传递给函数的参数在传递给函数体之前进行求值,而宏参数传递给宏体未评估(意味着宏体看到您输入的代码形式并且可以对纯代码进行操作) . 小例子:

    user> 
    (defn add2 [a]
      (println "a is" a)
      (+ a 2))
    #'user/add2
    
    user> (add2 (+ 10 10))
    a is 20
    22
    
    user> 
    (defmacro add2-m [a]
      (println "a is" a)
      `(+ ~a 2))
    #'user/add2-m
    
    user> (add2-m (+ 10 10))
    a is (+ 10 10)
    22
    

    这意味着构建日志记录功能将是不存在的,因为作为arg传递的基准测试代码将在第一个时间戳之前进行评估 .

    并且你想要的宏可能看起来像这样:

    (defmacro bm [form]
      `(let [start# (System/nanoTime)
             result# ~form
             end# (System/nanoTime)]
         (println "Took:" (- end# start#) "ns")
         result#))
    

    在编译时将其扩展为以下内容:

    ;;(bm (apply + (range 1E6)))
    ;;=> Took: 131009572 ns
    ;;=> 499999500000
    
    (let*
      [start__6355__auto__
       (. java.lang.System nanoTime)
       result__6356__auto__
       (apply + (range 1000000.0))
       end__6357__auto__
       (. java.lang.System nanoTime)]
      (println "Took:" (- end__6357__auto__ start__6355__auto__) "ns")
      result__6356__auto__)
    
  • 0

    这是一个非常好的网站,可以了解单引号以及如何正确使用它们https://8thlight.com/blog/colin-jones/2012/05/22/quoting-without-confusion.html

    作为旁注,我确信这项任务的目的是自己尝试而不是复制答案:) .

相关问题