2016-12-06 101 views
0

我想評估一個宏的參數是否是一個函數。如果是我想返回未評估的功能。否則返回一個不同的功能。像這樣:如何在clojure宏中測試未評估函數?

(defmacro func? [function] 
    (if (fn? function) 
    function 
    identity)) 
((func? "oops") 5) ;=> 5 
((func? -) 5)  ;=> 5 

然而上述失敗,因爲未計算的功能還不是真正功能得到這個工作,我必須使用邪惡的eval:

(defmacro func? [function] 
    (if (fn? (eval function)) 
    function 
    identity)) 
((func? "oops") 5) ;=> 5 
((func? -) 5)  ;=> -5 

如何避免使用在這裏評估? 答案必須是宏。

在我的情況下宏功能的原因是,這個宏被用於很多在我的遊戲中被調用很多次的函數。該宏是一個輸出格式解釋器。換句話說,我自己可以這樣寫,但宏使我的代碼更清晰。如果我使用了一個函數而不是這個宏,它會做同樣的解釋,只需要進行一次,每50ms重複我的遊戲大約60次。希望澄清而不是混淆我的情況。

+1

什麼是你正在試圖解決的實際問題?我不禁想到,那裏可能有更好的解決方案。 –

+0

我很抱歉無法與編譯時在運行時評估此函數的需求。問題已更新。 –

+0

這有幫助。但是,「輸出格式解釋器」是什麼意思?你可以添加一些例子,說明你真的想要如何使用這個宏(在上下文中)?你的例子沒有太大的意義。如何使'((func?「oops」)5)'評估爲'5'與你的「解釋器」有關? –

回答

2

您需要考慮宏的許多可能的參數,以決定它是否是函數。

  1. 它是一個符號嗎?一個號碼?一個字符串?
  2. 符號解析爲一個函數的變量?
  3. 該符號需要解析哪些名稱空間?

假設的功能,以解決居住在當前的命名空間,你可以做這樣的事情:

(defn test 
    [] 
    "result") 

(defmacro func? 
    [f] 
    (if (and (symbol? f) 
      (fn? (var-get (ns-resolve *ns* f)))) 
    f 
    identity)) 

(func? test) 
#object[user$test 0x37c27452 "[email protected]"] 

(func? 4) 
#object[clojure.core$identity 0x3a811e64 "[email protected]"] 

ns-resolvevar-get給你一個句柄到適當的函數值(或所有任何值情況f確實是解決某事的符號)。

在當前命名空間的工作解決了所有的功能,例如:

(:require [some.ns :as other-ns]) 

(func? other-ns/valid-fn) 
=> #object[some.ns$valid-fn 0x7207a00b "[email protected]"] 
+0

['resolve'](https://clojuredocs.org/clojure.core/resolve)可以在這裏用來代替'ns-resolve'。另外,所有的宏都需要一個隱含的['&env'](http://blog.jayfields.com/2011/02/clojure-and.html)參數,這個參數應該被用來處理本地定義的函數。不幸的是,我不認爲'&env'的細節被認爲是Clojure的公共API的一部分。 –

+1

另外,你可以簡單地使用'deref'(或'@')來取消引用'Var'。 –

2

爲什麼要使用宏?

(defn func? [function] 
    (if (fn? function) 
    function 
    identity)) 

((func? "oops") 5) ;=> 5 
((func? -) 5)  ;=> -5 

注意#(identity %)只是identity

+0

以上是一個簡化示例(不要以爲任何人都希望在這裏粘貼200行),因爲在編譯時只應調用一次這些變量。而不是在運行時多次調用。 –

+0

@JasonBasanese您可以關閉評估(在「def」或附屬的let中)以避免重複評估。除非你依賴* form *來產生可能的函數,否則我看不出它有助於在宏中構造計算。 – Thumbnail

+0

@JasonBasanese這是有道理的。您的案例讓我想起[clojure.spec]中[謂詞](https://clojure.org/guides/spec#_predicates)的作用。但這個問題似乎蒙上了一層陰影。也許你可以設法更公開地傳達你的困境。 – Thumbnail