Skip to content

Instantly share code, notes, and snippets.

@aoiroaoino
Last active September 16, 2019 06:28
Show Gist options
  • Select an option

  • Save aoiroaoino/f017458c29d0b98eeaf239529f04af22 to your computer and use it in GitHub Desktop.

Select an option

Save aoiroaoino/f017458c29d0b98eeaf239529f04af22 to your computer and use it in GitHub Desktop.
Scala秋祭り2019 発表資料内に登場するソースコードの元
def isEven(i: Int): Boolean = 1 % 2 == 0
val result = isEven(42)
if (result) {
println(s"$n is even number")
} else {
println(s"$n is odd number")
}
// ===
val result = isEven(42)
if (result) {
println(s"$n is even number") // 実行される
} else {
println(s"$n is odd number") // 実行されない(捨てられる)
}
// ===
def add(i: Int, j: Int): Int = i + j
def mul(i: Int, j: Int): Int = i * j
def show(i: Int): String = "num: " + i.toString
val a = add(1, 2)
val b = add(a, 3)
val s = show(b)
println(s)
// ===
def add(i: Int, j: Int): Int = i + j
def mul(i: Int, j: Int): Int = i * j
def show(i: Int): String = "num: " + i.toString
val a = add(1, 2) // 計算結果
// ↓ その後の計算
val b = mul(a, 3)
val s = show(b)
println(s)
// ===
def add(i: Int, j: Int): Int = i + j
def mul(i: Int, j: Int): Int = i * j
def show(i: Int): String = "num: " + i.toString
val a = add(1, 2)
val b = mul(a, 3) // 計算結果
// その後の計算
val s = show(b)
println(s)
// ===
def add(i: Int, j: Int): Int = i + j
def mul(i: Int, j: Int): Int = i * j
def show(i: Int): String = "num: " + i.toString
val a = add(1, 2)
val b = mul(a, 3)
val s = show(b) // 計算結果
// その後の計算
println(s)
// 通常の計算(直接スタイル)
def add(i: Int, j: Int): Int = i + j
// 継続渡しスタイル
def add[R](i: Int, j: Int)(cont: Int => R): R = {
val a = i + j
cont(a)
}
// 通常の計算(直接スタイル)
def show(i: Int): String = "num: " + i.toString
// 継続渡しスタイル
def show[R](i: Int)(cont: String => R): R = {
val a = "num: " + i.toString
cont(a)
}
// ===
scala> def add[R](i: Int, j: Int)(cont: Int => R): R = {
| val a = i + j
| cont(a)
| }
add: [R](i: Int, j: Int)(cont: Int => R)R
// 1 + 2 を実行。その後の計算で「10倍する」
scala> add(1, 2)(a => a * 10)
res0: Int = 30
// 1 + 2 を実行。その後の計算で「引数を返す」
scala> add(1, 2)(a => a)
res1: Int = 3
// ===
scala> def show[R](i: Int)(cont: String => R): R = {
| val a = "num: " + i.toString
| cont(a)
| }
show: [R](i: Int)(cont: String => R)R
// 1 を文字列に変換し prefix をつける。その後の計算「suffix をつける」
scala> show(1)(a => a + " !!")
res3: String = num: 1 !!
// 1 を文字列に変換し prefix をつける。その後の計算「Byte 配列を得る」
scala> show(1)(a => a.getBytes(java.nio.charset.StandardCharsets.UTF_8))
res4: Array[Byte] = Array(110, 117, 109, 58, 32, 49)
// ===
// 直接スタイル(再掲)
val a = add(1, 2)
val b = mul(a, 3)
val s = show(b)
println(s)
// ===
// 継続渡しスタイル
add(1, 2){ a =>
mul(a, 3){ b =>
show(b){ s =>
println(s)
}
}
}
// ===
// 継続ってどこだっけ?
def add[R](i: Int, j: Int)(cont: Int => R): R = {
val a = i + j
cont(a)
}
def show[R](i: Int)(cont: String => R): R = {
val a = "num: " + i.toString
cont(a)
}
// ===
// メソッド定義を再掲
def add[R](i: Int, j: Int)(cont: Int => R): R = { ??? }
def show[R](i: Int) (cont: String => R): R = { ??? }
// 継続部分を関数に変更
def add[R](i: Int, j: Int): (Int => R) => R = { cont => ??? }
def show[R](i: Int) : (String => R) => R = { cont => ??? }
// (A => R) => R という関数に Cont[R, A] と名前をつける
type Cont[R, A] = (A => R) => R
def add[R](i: Int, j: Int): Cont[R, Int] = { cont => ??? }
def show[R](i: Int) : Cont[R, String] = { cont => ??? }
// ===
// Scala ではしばしばラップするデータ型を定義
final case class Cont[R, A](run: (A => R) => R)
// もちろん、データ型 Cont[R, A] を用いて add, show が定義できる
def add[R](i: Int, j: Int): Cont[R, Int] = Cont { cont => ??? }
def show[R](i: Int) : Cont[R, String] = Cont { cont => ??? }
// ===
// Monad にしたい(for式で合成したい)
object Cont {
def pure[R, A](a: A): Cont[R, A] =
???
}
final case class Cont[R, A](run: (A => R) => R) {
def flatMap[B](f: A => Cont[R, B]): Cont[R, B] =
???
def map[B](f: A => B): Cont[R, B] =
???
}
// ===
// pure の実装
object Cont {
def pure[R, A](a: A): Cont[R, A] =
Cont(ar => ar(a)) // pure の実装
}
final case class Cont[R, A](run: (A => R) => R) {
def flatMap[B](f: A => Cont[R, B]): Cont[R, B] =
???
def map[B](f: A => B): Cont[R, B] =
???
}
// ===
// flatMap の実装 1
object Cont {
def pure[R, A](a: A): Cont[R, A] =
Cont(ar => ar(a))
}
final case class Cont[R, A](run: (A => R) => R) {
def flatMap[B](f: A => Cont[R, B]): Cont[R, B] =
Cont(br => ???) // 計算結果を考える
def map[B](f: A => B): Cont[R, B] =
???
}
// ===
// flatMap の実装 2
object Cont {
def pure[R, A](a: A): Cont[R, A] =
Cont(ar => ar(a))
}
final case class Cont[R, A](run: (A => R) => R) {
def flatMap[B](f: A => Cont[R, B]): Cont[R, B] =
Cont(br => run(a => f(a) /* Cont[R, B] */)) // 自身の継続として、引数の関数fにその結果を与える
def map[B](f: A => B): Cont[R, B] =
???
}
// ===
// flatMap の実装 3
object Cont {
def pure[R, A](a: A): Cont[R, A] =
Cont(ar => ar(a))
}
final case class Cont[R, A](run: (A => R) => R) {
def flatMap[B](f: A => Cont[R, B]): Cont[R, B] =
Cont(br => run(a => f(a).run(br))) // fに結果を与えて得られた継続に外側の継続を渡す
def map[B](f: A => B): Cont[R, B] =
???
}
// ===
// map はモナドのデフォルト実装
object Cont {
def pure[R, A](a: A): Cont[R, A] =
Cont(ar => ar(a))
}
final case class Cont[R, A](run: (A => R) => R) {
def flatMap[B](f: A => Cont[R, B]): Cont[R, B] =
Cont(br => run(a => f(a).run(br)))
def map[B](f: A => B): Cont[R, B] =
flatMap(a => Cont.pure(f(a))) // ひとまずモナドのデフォルト実装
}
// ===
def add[R](i: Int, j: Int): Cont[R, Int] = Cont(ar => ar(i + j))
def mul[R](i: Int, j: Int): Cont[R, Int] = Cont(ar => ar(i * j))
def show[R](i: Int): Cont[R, String] = Cont(ar => ar(s"num: $i"))
def prog[R]: Cont[R, String] =
for {
a <- add(1, 2)
b <- mul(a, 3)
s <- show(b)
} yield {
s.toUpperCase
}
// ===
// ===
def prog[R]: Cont[R, String] =
add(1, 2).flatMap { a =>
mul(a, 3).flatMap { b =>
show(b).map { s =>
s.toUpperCase
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment