1

このように 2 つの関数を書きましたが、ご覧のとおり、ほとんどの部分が同じなので、単純化するマクロを書きたいと思います。

教科書の簡単なマクロの例は理解できますが、自分で書く方法がわかりません。

これが私のコードです:

 (defn load-dict
       ;  "Load database from a txt file previous saved"
       [fname]
       (with-open [rdr (io/reader fname)]
                  (doseq [line (line-seq rdr)]
                         (println line)
                         (def vvv (clojure.string/split line #"\s"))
                         ;(println (str "count of vvv is " (count vvv)))
                         (if (< 1 (count vvv))
                           (add- dict (gen-word (nth vvv 0) (nth vvv 2) (nth vvv 1))))
                         )))
 (defn load-article
       ;  "Load article from a txt file"
       [fname]
       (with-open [rdr (io/reader fname)]
                  (doseq [line (line-seq rdr)]
                         (println line)
                         (def vvv (clojure.string/split line #"\s"))
                         ;(println (str "count of vvv is " (count vvv)))
                         (if (< 1 (count vvv))
                           (add- article vvv ))
                         )))

次のようなマクロを作成する必要があります。

(defmacro load- [target fname &expr)
  `(... 
    (add- ~target expr)))

私は実際にそのようなマクロを書く方法を知りません。私は重複したコードが嫌いです。

PS、牽引機能は正常に動作します。これがコードの一部である変数は気にしません。

4

2 に答える 2

5

def の代わりに let ブロックを使用します。def を使用すると、var がバインドされ、名前空間で vvv が定義されます。マクロは特に必要ありません。次のようにコードを単純化できます。

(defn load-from
   "Load database from a txt file previous saved"
   [fname load-fn]
   (with-open [rdr (io/reader fname)]
              (doseq [line (line-seq rdr)]
                     (println line)
                     (let [vvv (clojure.string/split line #"\s")]
                       (when (< 1 (count vvv))
                         (load-fn vvv))))))

そして、このように呼び出します

(load-from "myfile.txt" #(add- dict (apply gen-word (take 3 %))))
(load-from "myfile.txt" #(add- article %))
于 2013-07-30T15:41:48.980 に答える
3

user1944838 は、マクロを必要としないという点でここでは正しいです。マクロはコードを必要としないため、一部のコンテキストでの作業が少し難しくなるため (たとえば、に渡すことはできません)、関数を使用することmapapply実際には好ましい。ただし、マクロを正しく記述する方法を理解することは非常に重要です。

これをテンプレート マクロとして記述します。このテンプレート マクロは、渡す名前を各単語にバインドし、渡す本文をマクロに呼び出します。マクロは、その単語をシンボル名で使用します。

(defmacro with-loaded-article                                                                                                                                             
  [[name-for-line fname] & body]                                                                                                                                          
  `(with-open [rdr# (io/reader ~fname)]                                                                                                                                   
     (doseq [line# (line-seq rdr#)]                                                                                                                                       
       (println line#)                                                                                                                                                    
       (let [~name-for-line (clojure.string/split line# #"\s")]                                                                                                           
         ~@body)))) 
  • この[name-for-line fname]式は、最初の引数を、シンボルとそれが解決される値を生成するために使用される単一の「バインディング フォーム」に分解します。この形式は、「with-*」マクロなどで非常に一般的です。with-openただし、コードを小さく保つために、1 つのバインド形式のみを使用します。
  • syntax-quote 内のrdr#およびline#記号は、"auto gensyms" と呼ばれる構文引用の機能であり、構文引用の側にある # で終わる記号は、結果の式で一意ではあるが一貫した記号に置き換えられます。
  • これ~@は、syntax-quotes の splicing-unquote 機能であり、この場合、周囲にbody追加せずに挿入されます。( )

macroexpand-1これがとpprintヒントでどのように展開するかを見ることができます:(use 'clojure.pprint)

hello.core> (pprint (macroexpand-1 
                      `(with-loaded-article [line "tmp.txt"] (println line))))                                                                                 
(clojure.core/with-open                                                                                                                                                   
 [rdr__6337__auto__ (clojure.java.io/reader "tmp.txt")]                                                                                                                   
 (clojure.core/doseq                                                                                                                                                      
  [line__6338__auto__ (clojure.core/line-seq rdr__6337__auto__)]                                                                                                          
  (clojure.core/println line__6338__auto__)                                                                                                                               
  (clojure.core/let                                                                                                                                                       
   [hello.core/line (clojure.string/split line__6338__auto__ #"\s")]                                                                                                      
   (clojure.core/println hello.core/line))))                                                                                                                              

結果のコードを実行すると、ファイルの行がシーケンスとして取得されます。

hello.core> (with-loaded-article [line "tmp.txt"] (println line))                                                                                                         
hello world                                                                                                                                                               
[hello world]                                                                                                                                                             
world hello                                                                                                                                                               
[world hello]                                                                                                                                                             
and internet hello as well                                                                                                                                                
[and internet hello as well]
于 2013-07-30T17:04:44.393 に答える