2012-08-09 82 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 =虽然。