Clojure 如何制作';()是零吗?

Clojure 如何制作';()是零吗?,clojure,Clojure,如何使clojure将'()计数为nil 例如: 如何制作这样的东西 (if '() :true :false) ;to be :false ;Or easier (my-fun/macro/namespace/... (if '() :true :false)) :false 而不仅仅是如果。在各个方面 (= nil '()) or (my-something (= nil '())) true 并且每个代码都要(“()零)保存 我在想某种有规律的表达。它将查看代码并将'

如何使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
,但是有一些东西像
(rest'(1))
和许多其他东西是
'()
,我不知道如何处理它

我听说宏允许你建立自己的语言。我想换个clojure试试。所以这更多的是关于“clojure如何工作以及如何改变它?”而不是“我真的需要它来完成我的工作。”

谢谢你的帮助。

'()
nil
不是一回事-你为什么想要它呢

不过,您可能需要的是
seq
函数,如果给定一个空集合,该函数将返回nil:

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

(seq [])
=> nil

(seq '())
=> nil
因此,
seq
经常被用来测试“空虚”,成语如下:

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

空的呢?
?这是最有表现力的

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

您说您想使用宏更改Clojure。目前,据我所知,这不是“常规”宏系统所能做到的(术语修复了吗?)。我认为你真正需要的是一个阅读器宏。我在网上看到的东西(例如)似乎表明Clojure 1.4中存在类似于reader宏的东西——但我对此并不熟悉,因为我真的喜欢使用它作为我的IDE,而它目前没有使用Clojure 1.4。也许其他人对这种“可扩展阅读器”的魔力有更好的了解

无论如何,我真的不喜欢这样改变语言,我认为有一个潜在的非常好的选择:即Clojure函数

此函数接受任何集合并按原样返回该集合,如果该集合为空,则返回
nil
。这意味着无论您希望
()
返回
nil
,都应该将其包装为
而不是空的
。这个答案与上面mikera的答案非常相似,只是您不必将集合转换为序列(这可能很好)

在“手写”收藏的情况下,使用
seq
not 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

可以重写宏和函数。例如:

(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) ~@args))
不幸的是,您不能重写if,因为它是一种特殊形式,而不是宏。您必须用另一个宏包装代码

让我们将if*宏设置为具有常见lisp行为的if:

(defmacro if* [cond & args]
    `(if (classic-lisp ~cond) ~@args)
这样,我们可以用if*s替换所有ifs:

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

您应该能够加载文件并替换其中的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=though一起工作。

使用类似于Lisp的通用表示法,方便访问java库。一、 可能是,贴错了例子。我还想(+1(如果(=nil’())12))成为2。(seq(+1(if(=nil’())12))没有帮助。我认为Clojure方法更适合用于Java库(通常返回nil/null表示“未找到结果”)。我认为你最好还是接受Clojure的方法。”()在Clojure或Java中没有任何特殊意义。在可能在CL中使用“()”的情况下使用nil/null。我想让这个问题保持简单。但也许这是个错误。我相信编写简短的(common lisp-解释器…)将很容易,它允许在Clojure上运行common lisp或混合代码。这只是其中的一小部分。我理解你的答案,我对此表示感谢。但在另一方面,它就像:a:“我怎么能做某事?”b:“你不想那样做。”我很抱歉,但这并不能让我满意。(我真的很感谢您的努力。)@mikera您应该使用
if let
获取
seq
的返回值。一个选项是降级到足够旧的Clojure版本。空序列过去是nil,但现在改变了:我认为读卡器宏不适合这个任务。与其他lisp方言相比,在clojure中,它们非常有限。
=> (clojure-the-old-way (if '() :true :false) )
:false
(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))