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
43
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
42
From Scala/Clojure to Kotlin
lagenorhynque
0
18
TDD with RDD: Changed Developer Experience through Clojure/Lisp REPLs
lagenorhynque
0
37
My Favourite Book in 2024: Get Rid of Your Japanese Accent
lagenorhynque
1
65
Exploring Collections in JVM Languages through Internals of map Function
lagenorhynque
0
41
Kotlin Meets Data-Oriented Programming
lagenorhynque
0
44
Introduction to Tree Representations in RDB 2024
lagenorhynque
0
71
Boundary between Mutability and Immutability
lagenorhynque
0
77
Learning Modern Web API Styles from IDL: REST, GraphQL, gRPC
lagenorhynque
0
110
Other Decks in Programming
See All in Programming
SwiftUI API Design Lessons
niw
1
280
Compose Hot Reload is here, stop re-launching your apps! (Android Makers 2025)
zsmb
1
500
Kamal 2 – Get Out of the Cloud
aleksandrov
1
190
AWSで雰囲気でつくる! VRChatの写真変換ピタゴラスイッチ
anatofuz
0
150
Building a macOS screen saver with Kotlin (Android Makers 2025)
zsmb
1
150
複雑なフォームの jotai 設計 / Designing jotai(state) for Complex Forms #layerx_frontend
izumin5210
3
480
Deoptimization: How YJIT Speeds Up Ruby by Slowing Down / RubyKaigi 2025
k0kubun
0
780
大LLM時代にこの先生きのこるには-ITエンジニア編
fumiyakume
7
2.9k
Empowering Developers with HTML-Aware ERB Tooling @ RubyKaigi 2025, Matsuyama, Ehime
marcoroth
2
540
これだけは知っておきたいクラス設計の基礎知識 version 2
masuda220
PRO
24
6.3k
Amazon CloudWatchの地味だけど強力な機能紹介!
itotsum
0
150
Fiber Scheduler vs. General-Purpose Parallel Client
hayaokimura
1
100
Featured
See All Featured
Into the Great Unknown - MozCon
thekraken
37
1.7k
The Success of Rails: Ensuring Growth for the Next 100 Years
eileencodes
45
7.2k
Statistics for Hackers
jakevdp
798
220k
Making Projects Easy
brettharned
116
6.1k
Adopting Sorbet at Scale
ufuk
76
9.3k
Optimising Largest Contentful Paint
csswizardry
36
3.2k
RailsConf & Balkan Ruby 2019: The Past, Present, and Future of Rails at GitHub
eileencodes
135
33k
Dealing with People You Can't Stand - Big Design 2015
cassininazir
367
26k
Performance Is Good for Brains [We Love Speed 2024]
tammyeverts
9
750
We Have a Design System, Now What?
morganepeng
52
7.5k
GraphQLとの向き合い方2022年版
quramy
46
14k
Learning to Love Humans: Emotional Interface Design
aarron
273
40k
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