如何让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 :(得分:10)
'()
与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))
答案 1 :(得分:2)
你说你想用宏来改变Clojure。目前,据我所知,这不是你可以用“常规”宏系统做的事情(术语修复任何人?)。你真正需要的是什么(我认为)是一个读者宏。我在网上看过的东西(例如here)似乎说在Clojure 1.4中存在之类的读取器宏 - 但我对此并不熟悉,因为我真的很喜欢使用{ {3}}作为我的IDE,它目前没有使用Clojure 1.4。也许其他人有关于这种“可扩展读者”魔术的更好信息。
无论如何,我真的不喜欢以这种方式改变语言的想法,我认为有一个非常好的选择:即Clojure函数clooj。
此函数接受任何集合,并按原样返回该集合,如果该集合为空,则返回nil
。这意味着您希望()
返回nil
的任何地方,您应该将其not-empty
换行。这个答案与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
答案 2 :(得分:1)
empty?
怎么样?这是最具表现力的。
(if (empty? '())
:true
:false)
答案 3 :(得分: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) ~@args))
不幸的是,你不能覆盖if,因为它是一个特殊形式而不是宏。您必须使用另一个宏包装代码。
让if *宏成为具有common-lisp行为的if:
(defmacro if* [cond & args]
`(if (classic-lisp ~cond) ~@args)
有了这个,我们可以用if * s替换所有if:
(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)))
现在:
=> (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 =。