Skip to content

Instantly share code, notes, and snippets.

@lagenorhynque
Last active November 11, 2022 06:55
Show Gist options
  • Save lagenorhynque/602720880209a002a6116dbc1f1f1a32 to your computer and use it in GitHub Desktop.
Save lagenorhynque/602720880209a002a6116dbc1f1f1a32 to your computer and use it in GitHub Desktop.
Clojureコレクションで探るimmutableでpersistentな世界

Clojureコレクションで探る

immutableでpersistentな世界


(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])

twitter icon


  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!

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の実装のひとつ
  • mutableでephemeralな可変長配列

[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.Collections$Un
modifiableCollection/add (Collections.java:1067).
null

user=> (.add xs 4)  ; もとのリストは破壊的更新操作ができる
true
user=> xs
[1 2 3 4]
user=> ys  ; 変更不可能なビューにも波及する
[1 2 3 4]
  • コレクション(ここではList)に対する変更不可能なビュー
    • もとのコレクションやその要素がmutableならimmutableではない
    • もとのコレクションが(実質的に) immutableである、もしくはこのビューを介してのみ操作できる状態であれば実質的にimmutable
    • cf. java.util.Collection

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コレクションの全体像


Clojureコレクションに関するインターフェース

clojure collection interfaces

ref. Clojure Applied (p. 38)


参考: Scala不変コレクションのトレイト

scala immutable collection traits

ref. 可変コレクションおよび不変コレクション | Collections | Scala Documentation


Clojureコレクションの性能特性

clojure collection performance guarantees

ref. Clojure Performance Guarantees


Scala不変コレクション(列型)の性能特性

scala seq performance guarantees

ref. 性能特性 | Collections | Scala Documentation


Clojureのデータ構造の応用について気になったら

書籍 Clojure Applied を読もう

scala seq performance guarantees


Further Reading


Clojure


Scala

Java


Kotlin

JavaScript

Python

#!/usr/bin/env bash
# npm install -g reveal-md
reveal-md exploring-immutable-persistent-world-with-clojure-collections.md --theme night --highlight-theme monokai-sublime -w $@
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment