Upgrade to Pro — share decks privately, control downloads, hide ads and more …

From Java through Scala to Clojure

From Java through Scala to Clojure

JavaからScala、そしてClojureへ: 実務で活きる関数型プログラミング
JavaプログラマこそScalaやClojureを試してみよう!

Kent OHASHI

June 24, 2022
Tweet

More Decks by Kent OHASHI

Other Decks in Programming

Transcript

  1. 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])
  2. プライベート 岐阜出身 2012 年春〜: 東京 2022 年春〜: 千葉 仙台/ 宮城/

    東北に接点は( たぶん) なさそう が以前から気になっている🐬 仙台うみの杜水族館
  3. 仕事( オプト) オプトの は主に仙台拠点で 開発運用されていた 2017 年頃から東京の開発部門も関わり始める そのタイミングで東京所属の私もジョイン 2018 年には仙台拠点へ出張する機会も

    2021 年にフルリモートワーク前提で東京と仙台 の開発部門が統合された 現在も仙台在住のメンバーと日常的に一緒に仕事 している 広告運用支援ツール群
  4. year event 2011 大学( 法学部) 4 年で初めてプログラミングに 少し触れる: SQL, Java

    2012 前職の会社に新卒入社し、 Java での業務システム開発に携わり始める 2014 趣味で関数型言語に傾倒する: Haskell, Clojure, Erlang, Scala, OCaml, etc. 2015 Clojure, Haskell, Scala の勉強会に参加する ようになり、のちの同僚とも出会う
  5. year event 2016 オプトに中途入社し、 大規模なScala 開発を経験する 2017 開発中のプロダクトの小さなバッチに Clojure を社内初導入する

    2018 新規プロダクトのREST API 実装にClojure を 採用する 2019 新規プロダクトのGraphQL API 実装に Clojure を採用する 2021 開発チームを離れ、開発組織横断的な技術 マネジメント業務へ
  6. Java オブジェクト指向・非関数型言語 静的型付き言語 JVM 言語 関数型プログラミング関連機能が充実してきた cf. // メソッドの定義 jshell>

    void hello(Object x) { ...> System.out.println("Hello, %s!".formatted(x)); ...> } | created method hello(Object) // メソッドの呼び出し jshell> hello("Java") Hello, Java! jshell コマンド
  7. Scala オブジェクト指向・関数型言語 静的型付き言語 JVM 言語 オブジェクト指向に関数型が溶け込んだ言語 cf. // メソッドの定義 scala>

    def hello(x: Any): Unit = | println(s"Hello, $x!") | def hello(x: Any): Unit // メソッドの呼び出し scala> hello("Scala") Hello, Scala! scala コマンド
  8. Clojure 非オブジェクト指向・関数型言語 動的型付き言語 JVM 言語 オブジェクト指向を嫌い関数型を志向したLisp cf. + ;; 関数の定義

    user=> (defn hello [x] #_=> (println (str "Hello, " x "!"))) #'user/hello ;; 関数の呼び出し ( 適用 ) user=> (hello "Clojure") Hello, Clojure! nil clojure コマンド rebel-readline
  9. とあるプロダクトの Java コード ( 抜粋 ) return mediaProcessLogDao.selectMediaProcessLogs(baseDate, modifiedEntities).stream() .map(this::normalizeTargetIndexIfAdvertise)

    .collect(Collectors.groupingBy(MediaProcessLogEntity::getKey)) .entrySet().stream().collect(toMap( Map.Entry::getKey, group -> { List<MediaProcessLogEntity> entities = group.getValue(); if (entities.stream() .allMatch(MediaProcessLogEntity::isEmpty)) { return true; } return entities.stream() .filter(e -> !e.isEmpty()) .allMatch(MediaProcessLogEntity::isImported); }));
  10. Java: サンプルデータ jshell> record Entity(int key, String x) {} |

    created record Entity jshell> final var entities = List.of( ...> new Entity(3, "a"), ...> new Entity(1, "b"), ...> new Entity(2, "c"), ...> new Entity(1, "d"), ...> new Entity(1, "e") ...> ) entities ==> [Entity[key=3, x=a], Entity[key=1, x=b], Entity[k ... x=d], Entity[key=1, x=e]]
  11. Java: 命令型 (imperative) のアプローチ jshell> final var keyToEntities = ...>

    new HashMap<Integer, List<Entity>>(); ...> for (final var e : entities) { ...> final var es = keyToEntities.getOrDefault(e.key(), ...> new ArrayList<Entity>()); ...> es.add(e); ...> keyToEntities.put(e.key(), es); ...> } keyToEntities ==> {} jshell> keyToEntities keyToEntities ==> {1=[Entity[key=1, x=b], Entity[key=1, x=d], Entity[key=1, x=e]], 2=[Entity[key=2, x=c]], 3=[Entity[key=3, x=a]]}
  12. jshell> final var result = new HashMap<Integer, Boolean>(); ...> for

    (final var entry : keyToEntities.entrySet()) { ...> result.put(entry.getKey(), ...> entry.getValue().size() > 1); ...> } result ==> {} jshell> result result ==> {1=true, 2=false, 3=false}
  13. Java: 関数型 (functional) のアプローチ ※ REPL での行継続のため行末に . を置いている jshell>

    entities.stream(). ...> collect(Collectors.groupingBy(Entity::key)). ...> entrySet().stream(). ...> collect(Collectors.toMap( ...> Map.Entry::getKey, ...> group -> group.getValue().size() > 1 ...> )) $3 ==> {1=true, 2=false, 3=false}
  14. Scala: サンプルデータ scala> case class Entity(key: Int, x: String) //

    defined case class Entity scala> val entities = Seq( | Entity(3, "a"), | Entity(1, "b"), | Entity(2, "c"), | Entity(1, "d"), | Entity(1, "e"), | ) val entities: Seq[Entity] = List(Entity(3,a), Entity(1,b), Entity(2,c), Entity(1,d), Entity(1,e))
  15. Scala: 関数型 (functional) のアプローチ scala> entities. | groupBy(_.key). | view.

    | mapValues(_.length > 1). | toMap val res0: Map[Int, Boolean] = Map(1 -> true, 2 -> false, 3 -> false)
  16. Clojure: サンプルデータ user=> (def entities [#:entity{:key 3 #_=> :x "a"}

    #_=> #:entity{:key 1 #_=> :x "b"} #_=> #:entity{:key 2 #_=> :x "c"} #_=> #:entity{:key 1 #_=> :x "d"} #_=> #:entity{:key 1 #_=> :x "e"}]) #'user/entities
  17. 考察 : 命令型 (imperative) のアプローチ 2 種類の変数とfor 文によるループ処理 変数やメソッドの命名、レイアウトなどの工夫を しないとコードの意図が埋もれがち

    文(statement) が登場し、命令( コマンド) の並びとし て表現されている マップやリストが破壊的に更新されている: 可変 (mutable) データ 変数への再代入を封じる(Java では final を付ける) だけでも安心感が高まる
  18. 考察 : 関数型 (functional) のアプローチ リストをグルーピングし、マップの値を変換すると いう意図が関数/ メソッドで表されている 引数で振る舞いを指定している: 高階関数

    (higher-order function) 与えているのは無名関数(anonymous function)/ ラムダ式(lambda expression) cf. オブジェクト指向のStrategy パターン 関数型言語では汎用的で高機能な関数/ メソッド が標準で充実している
  19. イミュータビリティ (immutability; 不変性 ) 形容詞形: イミュータブル(immutable; 不変) 対義語: ミュータビリティ(mutability; 可変性)

    、 ミュータブル(mutable; 可変) もとのまま変化しない( させられない) 性質 凍結するイメージ? 🧊 破壊的な更新操作( 再代入、更新、削除) を提供せ ず、作成( 初期化) し、取得する( 読み取る) ことに 徹する
  20. 主なメリット 再利用性や拡張性が向上する 高凝集で疎結合な「モジュール」( ソフトウェア コンポーネント) に繋がる プログラミング言語に限らない例 Pipes & Filters

    Ports & Adapters ( ヘキサゴナルアーキテクチャ) Single Responsibility Principle (SRP) ( によるプレゼン) UNIX 哲学 Simple Made Easy Rich Hickey
  21. コミュニティイベント : Haskell : Lisp 系言語(Clojure, Common Lisp な ど)

    : Elixir : Scala Haskell-jp Shibuya.lisp fukuoka.ex/kokura.ex/ElixirImp rpscala
  22. 書籍 : Scala, Erlang, Clojure, Haskell cf. ( 原書続 編):

    Elixir, Elm, Idris Scala 『7 つの言語 7 つの世界』 Seven More Languages in Seven Weeks 『実践Scala 入門』 『Scala スケーラブルプログラミング 第4 版』 『Scala 関数型デザイン&プログラミング』
  23. Clojure cf. ( 原書第3 版) Haskell 『プログラミングClojure 第2 版』 Programming

    Clojure, Third Edition Getting Clojure Clojure Applied 『[増補改訂]関数プログラミング実践入門』 『プログラミングHaskell 第2 版』 『すごいHaskell たのしく学ぼう!』 『Haskell 入門 関数型プログラミング言語の基礎と 実践』
  24. OCaml Erlang Elixir 『プログラミングの基礎』 『プログラミング in OCaml 』 『プログラミングErlang 』

    『すごいErlang ゆかいに学ぼう!』 『プログラミングElixir (第2 版)』