3

'()としてカウントする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

4 に答える 4

11

'()と同じではありません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))
于 2012-08-09T07:35:42.340 に答える
2

あなたは、マクロを使用して Clojure を変更したいと言っています。現在、私が知る限り、これは「通常の」マクロ システムでは実行できないことです (用語を修正する人はいますか?)。本当に必要なのは (私が思うに) リーダー マクロです。私がオンラインで見たもの (たとえばhere ) によると、Clojure 1.4 にはリーダー マクロのようなものが存在するようです。 1.4。たぶん、他の誰かがこの「拡張可能なリーダー」の魔法についてより良い情報を持っているでしょう。

いずれにせよ、私はそのように言語を変更するという考えはあまり好きではありません。潜在的に非常に優れた代替手段があると思います。つまり、Clojure functionnot-emptyです。

この関数は任意のコレクションを受け取り、そのコレクションをそのまま返す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
于 2012-08-09T13:13:38.193 に答える
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 を 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 = でも動作するはずだと思います。

于 2012-08-10T16:40:39.707 に答える