1

式とその値を出力するデバッグ マクロを作成しようとしています。これは、lazy-seq を送信すると問題を引き起こします。これを (str を使用して) 文字列に変換すると、プログラムがハングするからです。トップレベルにある場合、レイジー seq を検出するのは簡単です。

(def foo (cycle [1 2]))
(= (type foo) clojure.lang.LazySeq) ;=> true

もちろん、別のコレクション内にネストされている場合、これは機能しません

(def bar (list (cycle [1 2])))
(= (type bar) clojure.lang.LazySeq) ;=> false

これに対処するには、次の 2 つのいずれかが必要です。

1: コレクションをチェックして、どこかにネストされたレイジー seq が含まれているかどうかを確認する関数。

2: ネストされた lazy-seq を評価せずにコレクションを文字列に変換する関数。次のようになります。

(str2 {:inf (cycle [1 2])}) => "{:inf #clojure.lang.LazySeq@e9383}"

Michał Marczyk の回答を使用して、このマクロを思いつきました。

(defmacro dbg-print [& rest]
  "Print out values or expressions in context"
  `(let [lazy-take# 5 ;when printing lazy-seq, how many elements to print
         symb-str# (map str '~rest)
         symb-evl# (reverse
                    (binding [*print-length* 10] 
                      (loop [coll# (list ~@rest) retur# '()]
                        (if (not (empty? coll#))
                          (recur (rest coll#) (cons (pr-str (first coll#)) retur#))
                          retur#))))
         pairs# (map #(str %1 %2 %3 %4) symb-str# (repeat ":") symb-evl# (repeat " "))
         str# (reduce str pairs#)]
     (println (format "%s\n" str#))))

それはこのように動作します:

(dbg-print (+ 1 3) (cycle [1 2])) ;=> (+ 1 3):4 (cycle [1 2]):(1 2 1 2 1 2 1 2 1 2 ...) 

また、ネストされたレイジー seq を処理できます。

(dbg-print (list (cycle [1 2]))) ;=> (list (cycle [1 2])):((1 2 1 2 1 2 1 2 1 2 ...)) 
4

2 に答える 2

4

組み込みの Vars*print-length*と/ファミリ関数を使用できます (文字列表現を出力するのではなく、戻り値として取得する場合を含む*print-level*) :prprintpr-str

(binding [*print-length* 3
          *print-level*  3]
  (prn ((fn explode []
          (repeatedly #(repeatedly explode))))))

これは印刷されます

(((# # # ...) (# # # ...) (# # # ...) ...) ((# # # ...) (# # # ...) (# # # ...) ...) ((# # # ...) (# # # ...) (# # # ...) ...) ...)

ここで、#s は、データ構造のそれらの部分が過去の下降のために省略されることを示し*print-level*...s は、データ構造のそれらの部分が過去の拡張のために省略されることを示します*print-length*

実際のデータが出力された 2 つの例を次に示します。

user> (binding [*print-length* 10]
        (prn (cycle [1 2 3])))
(1 2 3 1 2 3 1 2 3 1 ...)

user> (binding [*print-level* 10]
        (prn ((fn step [i]
                (lazy-seq (list i (step (inc i)))))
              0)))
(0 (1 (2 (3 (4 (5 (6 (7 (8 (9 #))))))))))

最後に、返された文字列の例:

user> (binding [*print-length* 2
                *print-level*  2]
        (prn-str ((fn explode []
                    (repeatedly #(repeatedly explode))))))
"((# # ...) (# # ...) ...)\n"

この機能は、問題の Var の docstring に記載されています。 および を参照(doc *print-length*)してください(doc *print-level*)

于 2013-06-14T04:18:29.847 に答える