ブログの更新頻度も上げていくつもりです。
Lens
Lensはあるフィールドに対するgetterとsetterを持つ。
コードにするとこんな感じ。
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(defprotocol Lens | |
(lget [lens object]) | |
(lset [lens object value])) | |
(defrecord Rational [numer denom]) | |
(def numer | |
(reify Lens | |
(lget [lens object] | |
(get object :numer)) | |
(lset [lens object value] | |
(assoc object | |
:numer value)))) | |
(def denom | |
(reify Lens | |
(lget [lens object] | |
(get object :denom)) | |
(lset [lens object value] | |
(assoc object | |
:denom value)))) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
user> (lget numer (->Rational 1 2)) | |
1 | |
user> (lset denom (->Rational 1 2) 3) | |
#lens.Rational{:numer 1, :denom 3} |
見てわかるとおり、lgetはgetで、lsetはassocで十分なのだ。
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
user> (get (->Rational 1 2) :numer) | |
1 | |
user> (assoc (->Rational 1 2) :denom 3) | |
#lens.Rational{:numer 1, :denom 3} |
Lensの特徴
getとsetがあればmodifyが定義できる。
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(defn modify [lens object f] | |
(lset lens object (f (lget lens object)))) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
user> (modify numer (->Rational 1 2) inc) | |
#lens.Rational{:numer 2, :denom 2} |
Clojureにはupdate-inがある。
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
user> (update-in (->Rational 1 2) [:numer] inc) | |
#lens.Rational{:numer 2, :denom 2} |
Lensは合成が可能だ。
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(defn compose [lens lens'] | |
(reify Lens | |
(lget [this object] | |
(lget lens (lget lens' object))) | |
(lset [this object value] | |
(lset lens (lget lens' object) value)))) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
user> (lget (compose numer denom) (->Rational 1 (->Rational 2 3))) | |
2 |
Clojureの{get, assoc, update}-in関数は複数のKeywordをとることで、ネストしたレコードに対しても有効です。
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
user> (get-in (->Rational 1 (->Rational 2 3)) [:denom :numer]) | |
2 |
LensはStateモナドと組み合わせると素敵です。
更新途中の状態を取得することは出来ないけれど、Clojureにはアローマクロが存在します。
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(defn add [rational {:keys [numer denom]}] | |
(-> rational | |
(update-in [:denom] (partial * denom)) | |
(update-in [:numer] #(+ (* % denom) (* numer (:denom rational)))))) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
user> (add (->Rational 1 2) (->Rational 2 3)) | |
#lens.Rational{:numer 7, :denom 6} |
KeywordがLensだということを意識すれば、Lensの考え方を応用することが出来ますね。