式とその値を出力するデバッグ マクロを作成しようとしています。これは、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 ...))