Threading Macroってなんだか難しそう....という先入観があった。
書いてみると難しくはないし、むしろ「Threading Macro使わないとかありえなくない?」となった。
ということで備忘録メモ。
そもそも何がやりたかったのか
階層構造になったMapの中の文字列を取り出して、1つの文字列を作りたかった。
dev> {:data {:operator "AND"
:values [{:value1 "hoge"
:value2 "fuga"}
{:value1 "HOGE"
:value2 "FUGA"}]}}
↓
"hoge,fuga AND HOGE,FUGA"
どうやってやるか
Threading Macroを使わない場合
dev> (defn func [{:keys [data]}]
(clojure.string/join
(str " " (:operator data) " ")
(map #(str (:value1 %) "," (:value2 %)) (:values data))))
#'dev/func
dev> (func {:data {:operator "AND"
:values [{:value1 "hoge"
:value2 "fuga"}
{:value1 "HOGE"
:value2 "FUGA"}]}})
"hoge,fuga AND HOGE,FUGA"
書きにくい、読みにくい、かっこ辛い。
Threading Macroを使う場合
dev> (defn func [{:keys [data]}]
(->> data
:values
(map #(str (:value1 %) "," (:value2 %)))
(clojure.string/join (str " " (:operator data) " "))))
#'dev/func
dev> (func {:data {:operator "AND"
:values [{:value1 "hoge"
:value2 "fuga"}
{:value1 "HOGE"
:value2 "FUGA"}]}})
"hoge,fuga AND HOGE,FUGA"
やりたいことを最下層から順番に書いただけ
->>
は、thread-last macro
というらしい。
対して、->
はthread-first macro
という。(何が出来るのかはもう名前から察せる。)
cf. https://clojure.org/guides/threading_macros
ちなみにこのマクロを展開すると...
dev> (macroexpand '(->> data
:values
(map
#(str (:value1 %) "," (:value2 %)))
(clojure.string/join (str " " (:operator data) " "))))
(clojure.string/join
(str " " (:operator data) " ")
(map
(fn* [p1__81698#] (str (:value1 p1__81698#) "," (:value2 p1__81698#)))
(:values data)))
最後に
ちなみに、Threading Macroの代表的なものとして他にsome->
, some->>
,cond->
あたりがある。
この辺はまた今度。