Clojureコレクションで探る
immutableでpersistentな世界
lagénorhynque 🐬カマイルカ
(defprofile lagénorhynque
:id @lagenorhynque
:readings ["/laʒenɔʁɛ̃
k/" "ラジェノランク"]
:aliases ["カマイルカ" "🐬"]
:languages [Java Japanese ; native languages
Clojure Haskell ; functional languages
English français] ; European languages
:interests [programming
language-learning
law politics
mathematics])
1. 改めて関数型プログラミング(言語)とは?
2. JavaとClojureのコレクションを調べてみよう
3. Clojureコレクションの全体像
4. 局所的にミュータビリティがほしいとき
5. 独自コレクションを実装しよう
改めて関数型プログラミング(言語)とは?
定義例
関数型プログラミング(functional programming;
FP)
副作用を可能な限り避ける(局所化する)プログラ
ミングスタイル
関数型プログラミング言語(functional
programming language; FPL)
関数型プログラミングが実践しやすいように設計
されている言語
再代入不可な変数が定義可能であればFPL?
const, final, val, etc.
それを活用していればFPしていることになる?
ラムダ式があり高階関数が豊富に提供されていれば
FPL?
filter, map, reduce, etc.
それを活用していればFPしていることになる?
確かにFP/FPLに近づいている感じがする。
でも、それで満足?
私🐬が期待する実用的なFPLのイメージ:
不変で永続的なデータ構造(immutable
persistent data structures) が豊富に提供さ
れ、容易に定義可能
そうでないデータ構造は非中心的な位置付け
i.e. immutableでpersistentがデフォルト
FP もできる言語をFPLと呼びたくはない
永続的(persistent)
関数型データ構造を更新する際には、更新前と更新
後のバージョンが両方ともその後の処理で利用でき
ることを期待する
複数のバージョンをサポートするデータ構造は永続
的(persistent)
←→ 同時に1つのバージョンしか許さないデータ
構造は刹那的(ephemeral)
FPLはすべてのデータ構造が自然と永続的になると
いう興味深い性質を持つ
命令型データ構造は概して刹那的
(p. 13)
『純粋関数型データ構造』
JavaとClojureのコレクションを調べてみよう
Java
オブジェクト指向・非関数型言語
静的型付き言語
JVM言語
関数型プログラミング関連機能が充実してきた
// メソッドの定義
jshell> void hello(Object x) {
...> System.out.println("Hello, %s!".formatted(x));
...> }
| created method hello(Object)
// メソッドの呼び出し
jshell> hello("Java")
Hello, Java!
Clojure
非オブジェクト指向・関数型言語
動的型付き言語
JVM言語
オブジェクト指向を嫌い関数型を志向したLisp
;; 関数の定義
user=> (defn hello [x]
(println (str "Hello, " x "!")))
#'user/hello
;; 関数の呼び出し(適用)
user=> (hello "Clojure")
Hello, Clojure!
nil
参考: Scala
オブジェクト指向・関数型言語
静的型付き言語
JVM言語
オブジェクト指向に関数型が溶け込んだ言語
// メソッドの定義
scala> def hello(x: Any): Unit =
| println(s"Hello, $x!")
def hello(x: Any): Unit
// メソッドの呼び出し
scala> hello("Scala")
Hello, Scala!
[Java]
の実装のひとつ
immutableでephemeralな可変長配列
java.util.ArrayList
user=> (def xs (java.util.ArrayList.))
#'user/xs
user=> xs
[]
user=> (def ys ; ysに束縛
#_=> (doto xs
#_=> (.add 1) ; 破壊的に要素追加
#_=> (.add 2)
#_=> (.add 3)))
#'user/ys
user=> ys
[1 2 3]
user=> (identical? xs ys) ; オブジェクトの同一性を確認
true
java.util.List
[Java] unmodifiable (view) list
user=> (def xs
#_=> (doto (java.util.ArrayList.)
#_=> (.add 1)
#_=> (.add 2)
#_=> (.add 3)))
#'user/xs
user=> xs
[1 2 3]
user=> (def ys (java.util.Collections/unmodifiableList xs)) ; 変
#'user/ys
user=> (.add ys 4) ; 破壊的更新操作はできない
Execution error (UnsupportedOperationException) at java.util.Col
modifiableCollection/add (Collections.java:1067).
null
コレクション(ここではList)に対する変更不可能な
ビュー
もとのコレクションやその要素がmutableなら
immutableではない
もとのコレクションが(実質的に) immutableであ
る、もしくはこのビューを介してのみ操作できる
状態であれば実質的にimmutable
cf.
user=> (.add xs 4) ; もとのリストは破壊的更新操作ができる
true
user=> xs
[1 2 3 4]
user=> ys ; 変更不可能なビューにも波及する
[1 2 3 4]
java.util.Collection
[Clojure]
の実装
immutableでpersistentな可変長配列
の一種
ベクター(vector)
user=> (def xs []) ; 初期化
#'user/xs
user=> xs
[]
user=> (def ys (conj xs 1 2 3)) ; 要素追加してysに束縛(破壊的更新操作
#'user/ys
user=> ys
[1 2 3]
user=> (identical? xs ys) ; オブジェクトの同一性を確認
false
clojure.lang.IPersistentVector
HAMT (hash array mapped trie)
Clojureコレクションの全体像
Clojureコレクションに関するインターフェース
ref. (p. 38)
Clojure Applied
参考: Scala不変コレクションのトレイト
Traversable
Iterable
Seq Set Map
IndexedSeq LinearSeq SortedSet SortedMap
BitSet
ref. 可変コレクションおよび不変コレクション|
Collections | Scala Documentation
Clojureコレクションの性能特性
ref. Clojure Performance Guarantees
Scala不変コレクション(列型)の性能特性
ref. 性能特性| Collections | Scala Documentation
Clojureのデータ構造の応用について気になったら
書籍 を読もう
Clojure Applied
Further Reading
Clojure
Clojure
Clojure - Data Structures
Clojure - Sequences
Clojure - Transient Data Structures
Clojure - Datatypes: deftype, defrecord and
reify
Clojure Applied: From Practice to Practitioner
Clojure Performance Guarantees [Stefan Tilkov’s
Blog]
clojure/core.rrb-vector: RRB-Trees in Clojure
Scala
Java
Scala
可変コレクションおよび不変コレクション|
Collections | Scala Documentation
性能特性| Collections | Scala Documentation
Java SE 17 & JDK 17
The Collections Framework (Java SE 17 & JDK
17)
Kotlin
JavaScript
Python
Kotlin/kotlinx.collections.immutable: Immutable
persistent collections for Kotlin
immutable-js/immutable-js: Immutable
persistent data collections for Javascript which
increase efficiency and simplicity.
tobgu/pyrsistent:
Persistent/Immutable/Functional data structures
for Python

Clojureコレクションで探るimmutableでpersistentな世界