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
54
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
純LISPから考える関数型言語のプリミティブ: Clojure, Elixir, Haskell, Scala
lagenorhynque
0
61
From Scala/Clojure to Kotlin
lagenorhynque
0
26
TDD with RDD: Changed Developer Experience through Clojure/Lisp REPLs
lagenorhynque
0
47
My Favourite Book in 2024: Get Rid of Your Japanese Accent
lagenorhynque
1
79
map関数の内部実装から探るJVM言語のコレクション: Scala, Kotlin, Clojureコレクションの基本的な設計を理解しよう
lagenorhynque
0
52
Kotlin Meets Data-Oriented Programming
lagenorhynque
0
52
Introduction to Tree Representations in RDB 2024
lagenorhynque
0
80
Boundary between Mutability and Immutability
lagenorhynque
0
87
Learning Modern Web API Styles from IDL: REST, GraphQL, gRPC
lagenorhynque
0
120
Other Decks in Programming
See All in Programming
Javaのルールをねじ曲げろ!禁断の操作とその代償から学ぶメタプログラミング入門 / A Guide to Metaprogramming: Lessons from Forbidden Techniques and Their Price
nrslib
1
240
技術懸念に立ち向かい 法改正を穏便に乗り切った話
pop_cashew
0
820
「兵法」から見る質とスピード
ickx
0
200
少数精鋭エンジニアがフルスタック力を磨く理由 -そしてAI時代へ-
rebase_engineering
0
130
Interface vs Types ~型推論が過多推論~
hirokiomote
1
230
TypeScript を活かしてデザインシステム MCP を作る / #tskaigi_after_night
izumin5210
4
480
Proxmoxをまとめて管理できるコンソール作ってみました
karugamo
1
410
try-catchを使わないエラーハンドリング!? PHPでResult型の考え方を取り入れてみよう
kajitack
3
320
REST API設計の実践 – ベストプラクティスとその落とし穴
kentaroutakeda
2
320
List Unfolding - 'unfold' as the Computational Dual of 'fold', and how 'unfold' relates to 'iterate'"
philipschwarz
PRO
0
130
"使いづらい" をリバースエンジニアリングする UI の読み解き方
rebase_engineering
0
110
AI Coding Agent Enablement in TypeScript
yukukotani
17
7.2k
Featured
See All Featured
4 Signs Your Business is Dying
shpigford
183
22k
Adopting Sorbet at Scale
ufuk
76
9.4k
A Tale of Four Properties
chriscoyier
159
23k
RailsConf & Balkan Ruby 2019: The Past, Present, and Future of Rails at GitHub
eileencodes
137
34k
Designing Dashboards & Data Visualisations in Web Apps
destraynor
231
53k
For a Future-Friendly Web
brad_frost
178
9.7k
Templates, Plugins, & Blocks: Oh My! Creating the theme that thinks of everything
marktimemedia
30
2.4k
Fireside Chat
paigeccino
37
3.5k
Principles of Awesome APIs and How to Build Them.
keavy
126
17k
Become a Pro
speakerdeck
PRO
28
5.4k
Connecting the Dots Between Site Speed, User Experience & Your Business [WebExpo 2025]
tammyeverts
1
79
Gamification - CAS2011
davidbonilla
81
5.3k
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