2012-08-09 83 views
1

如何讓clojure數'()nil如何使'()爲零?

例如: 如何使類似

(if '() :true :false) 

;to be 

:false 

;Or easier 

(my-fun/macro/namespace/... (if '() :true :false)) 

:false 

而且不只是如果。各方面。

(= nil '()) or (my-something (= nil '())) 

true 

並且每個代碼都被保存(='()nil)。

(something (+ 1 (if (= nil '()) 1 2))) 

2 

我在考慮某種表達方式。它會看代碼並用nil代替'(),但有一些東西,如(rest '(1))和許多其他的'(),我不知道如何處理它。

有人告訴我,宏允許你創建自己的語言。我想通過改變clojure來嘗試它。所以這很大程度上是關於「clojure如何工作以及如何改變它?」比「我真的需要它來爲我的工作。」

謝謝你的幫助。

+0

一種選擇是降級到Clojure的足夠舊版本。空的序列曾經是零,但是這個已經改變了:http://blog.n01se.net/blog-n01se-net-p-39.html – 2012-08-09 09:14:17

回答

2

你說你想改變使用宏的Clojure。目前,據我所知,這是不是你可以用「常規」宏觀系統(術語解決任何人?)做的事情?你真的需要什麼(我認爲)是一個閱讀器宏。我在網上看過的東西(例如here)似乎說在Clojure 1.4中存在類似閱讀器宏 - 但我對此並不熟悉,因爲我非常喜歡使用clooj作爲我的IDE,而且它目前不是使用Clojure 1.4。也許其他人有更好的信息在這個「可擴展的讀者」魔術。無論如何,我不太喜歡以這種方式改變語言的想法,我認爲這有一個潛在的非常好的選擇:即Clojure功能not-empty

此函數接受任何集合並按原樣返回該集合,如果該集合爲空,則返回nil。這意味着,任何你想要()返回nil,你應該把它包裝not-empty。這個答案與上面的mikera的答案非常相似,只不過你不需要轉換爲序列(這可能很好)。

在使用「手寫」集合的情況下,使用seqnot-empty這兩種方法都非常愚蠢。畢竟,如果你是手工編寫它(或者說,手動輸入),那麼你肯定知道它是否是空的。這很有用的情況是,當你有一個表達式或一個返回一個集合的符號時,你不知道返回的集合是否爲空。

例子:

=> (if-let [c (not-empty (take (rand-int 5) [:a :b :c :d]))] 
    (println c) 
    (println "Twas empty")) 
;//80% of the time, this will print some non-empty sub-list of [:a :b :c :d] 
;//The other 20% of the time, this will return... 
Twas empty 
=> nil 
+0

它看起來像讀者宏是我正在尋找。 – boucekv 2012-08-10 07:10:05

+0

我不認爲讀者宏適合這項任務。在clojure中,與其他lisp方言相比,它們非常有限。 – 2012-08-10 16:44:51

10

'()只是與nil不一樣 - 你爲什麼要這樣做?

什麼,你可能會雖然尋找的是seq功能,如果給一個空的集合,它返回零:

(seq [1 2 3]) 
=> (1 2 3) 

(seq []) 
=> nil 

(seq '()) 
=> nil 

seq因此通常用於測試「空虛」,慣用語,如:

(if (seq coll) 
    (do-something-with coll) 
    (get-empty-result)) 
+0

讓Common Lisp能夠像Java庫一樣輕鬆訪問。 我可能會發布錯誤的示例。我也想(+1(if(= nil'())1 2))爲2.(seq(+ 1(if(= nil'())1 2)))沒有幫助。 – boucekv 2012-08-09 07:59:25

+3

我認爲Clojure方法更適合與Java庫一起使用(它通常返回nil/null表示「找不到結果」)。我認爲你可能最好採用Clojure方法。 '()在Clojure或Java中沒有任何特殊含義。在CL中可能使用'()'的情況下使用nil/null。 – mikera 2012-08-09 08:10:28

+0

我想讓這個問題簡單。但也許這是錯誤的。我相信編寫簡短的(common-lisp-interpreter ...)將很容易,它允許在Clojure上運行Common Lisp或混合代碼。這只是其中的一小部分。我明白你的答案,我很感激。但另一方面,它是這樣的:a:「我怎麼能做點什麼?」 b:「你不想那麼做。」我很抱歉,但這並不能令我滿意。 (我非常感謝你的努力。) – boucekv 2012-08-09 08:26:31

1

empty?怎麼樣?這是最有表現力的。

(if (empty? '()) 
    :true 
    :false) 
1

您可以覆蓋宏和函數。例如:

(defn classic-lisp [arg] 
    (if (seq? arg) (seq arg) arg)) 

(defn = [& args] 
    (apply clojure.core/= (map classic-lisp args))) 

(defmacro when [cond & args] 
    `(when (classic-lisp ~cond) [email protected])) 

不幸的是,你不能重寫,如果,因爲它是一種特殊形式,而不是一個宏。你將不得不用另一個宏包裝你的代碼。

讓我們做的,如果*宏是如果有共識,口齒不清的行爲:

(use 'clojure.walk) 
(defn replace-ifs [code] 
    (postwalk-replace '{if if*} (macroexpand-all code))) 
(defmacro clojure-the-old-way [& body] 
    `(do [email protected](map replace-ifs body))) 

現在:

(defmacro if* [cond & args] 
    `(if (classic-lisp ~cond) [email protected]) 

有了這個,我們可以與如果* S全部替換IFS

=> (clojure-the-old-way (if '() :true :false)) 
:false 

您應該可以加載文件並替換ifs:

(defn read-clj-file [filename] 
    ;; loads list of clojure expressions from file *filename* 
    (read-string (str "(" (slurp filename) ")"))) 

(defn load-clj-file-the-old-way [filename] 
    (doseq [line (replace-ifs (read-clj-file filename))] (eval line)) 

請注意,我沒有測試加載文件的代碼,它可能與leiningen或命名空間不兼容。我相信它應該與overriden =雖然。