Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
do Notation Equivalents in JVM languages: Scala...
Search
Kent OHASHI
November 22, 2024
Programming
0
16
do Notation Equivalents in JVM languages: Scala, Kotlin, Clojure
Haskellでお馴染みのdo記法(do notation)がJVM言語Scala, Kotlin, Clojureでは言語機能やライブラリ実装としてどのように実現されているか、簡単に探ってみよう。
Kent OHASHI
November 22, 2024
Tweet
Share
More Decks by Kent OHASHI
See All by Kent OHASHI
My Favourite Book in 2024: Get Rid of Your Japanese Accent
lagenorhynque
0
20
Exploring Collections in JVM Languages through Internals of map Function
lagenorhynque
0
25
Kotlin Meets Data-Oriented Programming
lagenorhynque
0
30
Introduction to Tree Representations in RDB 2024
lagenorhynque
0
44
Boundary between Mutability and Immutability
lagenorhynque
0
56
Learning Modern Web API Styles from IDL: REST, GraphQL, gRPC
lagenorhynque
0
90
Team Geek Revisited
lagenorhynque
0
72
Scala vs Clojure?: The Rise and Fall of Functional Languages in Opt Technologies
lagenorhynque
0
130
Exploring Immutable Persistent World with Clojure Collections
lagenorhynque
0
120
Other Decks in Programming
See All in Programming
生成AIでGitHubソースコード取得して仕様書を作成
shukob
0
610
PHPで作るWebSocketサーバー ~リアクティブなアプリケーションを知るために~ / WebSocket Server in PHP - To know reactive applications
seike460
PRO
2
760
ある日突然あなたが管理しているサーバーにDDoSが来たらどうなるでしょう?知ってるようで何も知らなかったDDoS攻撃と対策 #phpcon.2024
akase244
2
7.7k
Оптимизируем производительность блока Казначейство
lamodatech
0
920
AppRouterを用いた大規模サービス開発におけるディレクトリ構成の変遷と問題点
eiganken
1
420
EC2からECSへ 念願のコンテナ移行と巨大レガシーPHPアプリケーションの再構築
sumiyae
3
570
ATDDで素早く安定した デリバリを実現しよう!
tonnsama
1
1.5k
Beyond ORM
77web
11
1.5k
Simple組み合わせ村から大都会Railsにやってきた俺は / Coming to Rails from the Simple
moznion
2
1.7k
今年のアップデートで振り返るCDKセキュリティのシフトレフト/2024-cdk-security-shift-left
tomoki10
0
350
歴史と現在から考えるスケーラブルなソフトウェア開発のプラクティス
i10416
0
290
Запуск 1С:УХ в крупном энтерпрайзе: мечта и реальность ПМа
lamodatech
0
920
Featured
See All Featured
Put a Button on it: Removing Barriers to Going Fast.
kastner
59
3.6k
実際に使うSQLの書き方 徹底解説 / pgcon21j-tutorial
soudai
172
50k
I Don’t Have Time: Getting Over the Fear to Launch Your Podcast
jcasabona
29
2.1k
Statistics for Hackers
jakevdp
797
220k
Making Projects Easy
brettharned
116
6k
Designing on Purpose - Digital PM Summit 2013
jponch
116
7.1k
Git: the NoSQL Database
bkeepers
PRO
427
64k
jQuery: Nuts, Bolts and Bling
dougneiner
62
7.6k
Refactoring Trust on Your Teams (GOTO; Chicago 2020)
rmw
33
2.7k
Distributed Sagas: A Protocol for Coordinating Microservices
caitiem20
330
21k
Designing Experiences People Love
moore
139
23k
Agile that works and the tools we love
rasmusluckow
328
21k
Transcript
do Notation Equivalents in JVM languages: Scala, Kotlin, Clojure 1
のシニアエンジニア スタートアップの起業家と投資家のための業務効 率化 連携プラットフォームを開発している 主要技術スタック の運営企業 などの関数型⾔語と関数型プログ ラミングの実践が好き と ⾔語での開発実務
に⻑く取り組んできた lagénorhynque カマイルカ 株式会社スマートラウンド 2
での発表テーマ JJUG CCC 2024 Fall map関数の内部実装から探るJVM⾔語のコレクション 3
Haskellの do 記法 4
モナドを扱い始めると >>= (bind)演算⼦がネストして いく(⼀種のcallback hell) 先⾏する計算の⽂脈を引き継ぐという意味では⾃然な 表現かも 読み書きにはあまり優しくないが λ> :{
λ| -- 例としてMaybe λ| Just 2 >>= \x -> λ| Just 10 >>= \y -> λ| return $ x ^ y λ| :} Just 1024 it :: Num b => Maybe b 5
簡潔に書き換える構⽂として do 記法がある のように ネストしたコードではなく 命令型の プログラム⾵のフラットなコードになる λ> :{ λ|
do λ| x <- Just 2 λ| y <- Just 10 λ| return $ x ^ y λ| :} Just 1024 it :: Num b => Maybe b λ> :{ -- リストに対しても同様に λ| do λ| x <- [1, 2, 3] λ| y <- [4, 5] λ| return $ x * y λ| :} [4,5,8,10,12,15] it :: Num b => [b]
Scalaの場合 7
モナドに相当する構造を扱い始めると flatMap, map がネストしていく // 例としてOption scala> Some(2).flatMap(x => |
Some(10).map(y => | scala.math.pow(x, y).toInt | ) | ) val res0: Option[Int] = Some(1024) 8
簡潔に書き換える構⽂として for 式がある scala> for | x <- Some(2) |
y <- Some(10) | yield scala.math.pow(x, y).toInt val res1: Option[Int] = Some(1024) // Seqに対しても同様に scala> for | x <- Seq(1, 2, 3) | y <- Seq(4, 5) | yield x * y val res2: Seq[Int] = List(4, 5, 8, 10, 12, 15) 9
Kotlinの場合 10
nullable (nullになりうる値)に対して >>> import kotlin.math.pow >>> (2.0 as Double?)?.let {
x -> ... (10.0 as Double?)?.let { y -> ... x.pow(y).toInt() ... } ... } res1: kotlin.Int = 1024 11
Iterableに対して >>> listOf(1, 2, 3).flatMap { x -> ... listOf(4,
5).map { y -> ... x * y ... } ... } res2: kotlin.collections.List<kotlin.Int> = [4, 5, 8, 10, 12, 15] 12
ライブラリ の 関数を利⽤する Arrow nullable import arrow.core.raise.nullable import kotlin.math.pow nullable
{ val x = (2.0 as Double?).bind() val y = (10.0 as Double?).bind() x.pow(y).toInt() } 13
ライブラリでの実例 らしく関数型の設計パターンを実装し ているライブラリ 関数 関数 関数 関数 関数 モナドライブラリ 関数
14
Clojureの場合 15
nilable (nilになりうる値)に対して user> (when-let [x 2] (when-let [y 10] (long
(clojure.math/pow x y)))) 1024 16
seqable (シーケンス化できる値)に対して ;; mapcat (= map + concat)とmap user> (mapcat
(fn [x] (map (fn [y] (* x y)) [4 5])) [1 2 3]) (4 5 8 10 12 15) ;; forマクロ(内包表記) user> (for [x [1 2 3] y [4 5]] (* x y)) (4 5 8 10 12 15) 17
モナドをプロトコルとして抽象化してみる (defprotocol Monad (return [this x]) (bind [this f m]))
18
do記法相当の構⽂をマクロとして定義する (defmacro mlet [monad bindings & body] (if-some [[sym m
& bindings] (seq bindings)] `(bind ~monad (fn [~sym] (mlet ~monad ~bindings ~@body)) ~m) `(return ~monad (do ~@body)))) 19
Monad プロトコルのメソッドに対する実装を与える ;; nilableに対する実装 (def nilable-monad (reify Monad (return [_
x] (identity x)) (bind [_ f m] (when (some? m) (f m))))) ;; seqableに対する実装 (def seqable-monad (reify Monad (return [_ x] (list x)) (bind [_ f m] (mapcat f m)))) 20
mlet マクロを使ってみる ;; nilable値の場合 do-notation> (mlet nilable-monad [x 2 y
10] (long (clojure.math/pow x y))) 1024 ;; seqable値の場合 do-notation> (mlet seqable-monad [x [1 2 3] y [4 5]] (* x y)) (4 5 8 10 12 15) 21
mlet マクロを使った式を展開してみる do-notation> (clojure.walk/macroexpand-all '(mlet ...省略...)) (do-notation/bind nilable-monad (fn* ([x]
(do-notation/bind nilable-monad (fn* ([y] (do-notation/return nilable-monad (do (long (clojure.math/pow x y)))))) 10))) 2) 22
ライブラリでの実例 の 実装 マクロ モナドライブラリ マクロ モナドを含む 圏論に由来する抽象 を扱うライブラリ マクロ
23
の 記法、 の 式が他⾔語でも たまにほしくなる メタプログラミングによる 構築は楽しい 24
Further Reading Haskell Scala 25
Kotlin 26
Clojure ドクセル 27