Programmer's Note

コード読み書きの備忘録。

続Clojureのdestructuringメモ

前回「 Clojureのdestructuringメモ - Programmer's Note 」の続き。

マップのdestructuring

文字列をキーに使った場合を試す
(def mab {"a" 1 "b" 2})
(let [{:strs [a b]} mab]
    (println b "," a))
; 結果 => 2,1

Goood!!

下記非短縮形もOK

(def mab {"a" 1 "b" 2})
(let [{x "a" y "b"} mab]
  (println x y))
シンボルがキーの場合
(def mcd {'c 1 'd 2})
(let [{:syms [c d]} mcd]
    (println c "," d))
; 結果 => 1,2

Goooooood!!

下記非短縮形もOK

(def mcd {'c 1 'd 2})
(let [{x 'c y 'd} mcd]
  (println y "," x))
さて、マップの入れ子構造も試してみる
(def dat {:name "boo"
          :body {:weight 60
                 :height 160 }
          :money 100})
(let [{{h :height} :body} dat]
  (println h))
; 結果 => 160
ベクターとマップの組み合わせ!

マップの中にベクターがある場合。

(def dat {:name "boo"
          :body [60 160]
          :money 100})
(let [{[_ height] :body} dat]
  (println height))
; 結果 => 160

ベクターの中にマップがある場合。

(def dat ["boo"
          {:weight 60 :height 160}
          100])
(let [[_ {h :weight} _] dat]
  (println h))
; 結果 => 60

なんつービューティフルな言語なんだ!

関数に引数をマップで与える場合の省略形

たとえば関数にパラメータでマップを渡したい場合、

(boo "foo" {:weight 50 :height 120})

にするが、これを

(boo "foo" :weight 50 :height 120)

のように書ける!

前者の関数定義は

(defn boo [name opts]
  (let [{w :weight h :height} opts]
    (println name ": (" w "," h ")")))

で、後者は

(defn boo [name & opts]
  (let [{w :weight h :height} opts]
    (println name ": (" w "," h ")")))

違いは引数の定義に&を使っているだけ! defnは実はマクロで、& optsと定義したときは、残りの引数をまとめてシーケンスに入れてくれる。 さらにシーケンスはベクターにもマップにも展開できる。 シーケンスという一個上位の抽象概念をかますと、物事をシンプルに扱える。美しい。

destructuringは関数の引数定義[]でも同じように使えるから、後者はこのようにも書ける。

(defn boo [name & {w :weight h :height}]
    (println name ": (" w "," h ")"))

いやあClojure最高です。