Clojure座談会 #1 LT 独自コレクションを定義しよう

13
独独独独独独独独独独独独独独 Clojure 独独独 #1 on 2015/09/12 @keisukefukuda

Transcript of Clojure座談会 #1 LT 独自コレクションを定義しよう

Page 1: Clojure座談会 #1 LT 独自コレクションを定義しよう

独自コレクションを定義しようClojure 座談会 #1 on 2015/09/12@keisukefukuda

Page 2: Clojure座談会 #1 LT 独自コレクションを定義しよう

なぜ Clojure か• Clojure は完全に趣味• なぜ Clojure か

• 趣味なので、「本質的に学ぶところがある」言語をやりたい• Go とか流行ってるけど本質的に新しくはないし• Scala 試して死んだ → そもそも俺は C++ で荒れた心を休めたいんだよ• Clojure 、 Haskell 、 Erlang ( Elixir )くらい?• といいつつある程度の実用性( JVM, Heroku )• Minecraft とかの拡張書けるんじゃね?(まだ試してない)

Page 3: Clojure座談会 #1 LT 独自コレクションを定義しよう

Clojure の思想(の 1 つ)"It is better to have 100 functions operate on one data structure than to have 10 functions operate on 10 data structures." - Alan J. Perlis

from http://clojure.org/rationale

10 のデータ構造のそれぞれに 10 個ずつ関数を作るよりも、1 個のデータ構造に 100 個の関数がある方が良い

Page 4: Clojure座談会 #1 LT 独自コレクションを定義しよう

(だいたい)なんでも map, vector, set• クラスを作ってメソッド実装というのは(あまり)やらない• だいたい map でおk• clojure の大量の関数がそのまま使える

Page 5: Clojure座談会 #1 LT 独自コレクションを定義しよう

だけど• 独自のデータ型が欲しい場合もある• 例:

• 基本的には map で良いが、一部の要素を遅延評価したい• PDF パーザーを書いているときの実体験

{:a 1 :b (delay (do-something-1)) :c (future (do-something-2)) :d 2}

(let [a (:a m)] (let [a (if (instance? clojure.lang.IDeref a) @a a)] ……))

Page 6: Clojure座談会 #1 LT 独自コレクションを定義しよう

だけど• 独自のデータ型が欲しい場合もある• 例:

• 基本的には map で良いが、一部の要素を遅延評価したい• PDF パーザーを書いているときの実体験

{:a 1 :b (delay (do-something-1)) :c (future (do-something-2)) :d 2}

(let [a (get-a m)] ……)

メソッド定義する?

Page 7: Clojure座談会 #1 LT 独自コレクションを定義しよう

そこで• Clojure の map などは、実装レベルでは Java のクラス• Clojure では Java のクラスを定義できる

• 組み込みデータ型と同じように振る舞う独自型を定義すればいいんじゃね?

Page 8: Clojure座談会 #1 LT 独自コレクションを定義しよう

http://www.rkn.io/2014/02/20/clojure-cookbook-rbt/

Page 9: Clojure座談会 #1 LT 独自コレクションを定義しよう

やってみる• clojure.lang.APersistentMap が implement しているインターフェース

• clojure.lang.Associative• clojure.lang.IPersistentMap• clojure.lang.IPersistentCollection• clojure.lang.IFn• clojure.lang.ILookup• java.util.Map• java.lang.Iterable• clojure.lang.Seqable• clojure.lang.Reversible

Page 10: Clojure座談会 #1 LT 独自コレクションを定義しよう

やってみる(deftype MyMap1 [ks f] clojure.lang.Associative clojure.lang.IPersistentMap (entryAt [this k] (if (some #{k} ks) (reify clojure.lang.IMapEntry (key [this] k) (val [this] (f k))) nil))

(assoc [this key val] this)

(assocEx [this key val] (throw (Exception. "error")))

(without [this key] this)

clojure.lang.IFn (invoke [this k] (let [v (.valAt this k)] v))

clojure.lang.ILookup (valAt [this k] (if (some #{k} ks) (f k) nil))

(valAt [this k not-found] (if (some #{k} ks) (.valAt this k)

not-found))

clojure.lang.IPersistentCollection (count [_] (.count ks)) (empty [_] (.empty ks)) (equiv [this o] (and (instance? o MyMap1) (= (keys o) ks) (= (vals o) (map f keys))))

(cons [_ v] _)

java.lang.Iterable (iterator [this] (let [s (seq this)] (reify java.util.Iterator (hasNext [this] (.hasNext s)) (next [this] (.next s)) (remove [this] (.remove s)))))

clojure.lang.Seqable (seq [_] (map #(reify java.util.Map$Entry (getKey [_] %) (getValue [_] (f %))) ks))

clojure.lang.Reversible (rseq [_] (reverse (seq _))))

Page 11: Clojure座談会 #1 LT 独自コレクションを定義しよう

ライブラリ化しよう• 作業中

Page 12: Clojure座談会 #1 LT 独自コレクションを定義しよう

ブログにも少し書きましたhttp://freak-da.hatenablog.com/

Page 13: Clojure座談会 #1 LT 独自コレクションを定義しよう

Question?