如何使'()成为零?

时间:2012-08-09 07:18:09

标签: 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

每个代码都是(='()nil)保存。

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

2

我在想某种自然的表达方式。哪个会查看代码并将'()替换为nil,但有些内容如(rest '(1))和其他许多内容'(),我不知道如何处理它。

有人告诉我,宏可以让你建立自己的语言。我想通过改变clojure来尝试它。所以这很大关于“如何使用clojure以及如何改变它?”比“我真的需要它来做我的工作。”

感谢您的帮助。

4 个答案:

答案 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上面的答案非常相似,只是你没有 将你的集合转换为序列(这可能很好)。

使用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

答案 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 =。