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

Scalaはいいぞ

Avatar for kokoroszk kokoroszk
May 18, 2026
25

 Scalaはいいぞ

Avatar for kokoroszk

kokoroszk

May 18, 2026

Transcript

  1. 自己紹介 株式会社ヌーラボ 鈴木 心 (@kokoroszk) Scala で求人を探して転職して4 年目 入社後、主にTypeScript とRust

    を書いています(!? ) 趣味: 音楽、調味料 勉強会で登壇するのは初めてです! Scala はいいぞ 2
  2. 雑談: Scala の好きなところ 特殊な構文が少ない Typescript の場合 // 配列の処理で特殊な記号[] を使う const

    arr = [1, 2, 3]; // 配列を生成する特殊な記号[] arr[1]; // 要素にアクセスする特殊な記号[] // 四則演算に特殊な記号+,-,*,/ を使う 1 + 2; // 加算を行う特殊な記号 + // 値を返す条件式に特殊な記号 ? : を使う const result = x > 10 ? "large" : "small"; Scala はいいぞ 4
  3. 雑談: Scala の好きなところ 特殊な構文が少ない Scala の場合 // apply メソッドの呼び出し。apply メソッドは関数名の省略が可能。

    val list = List(1, 2, 3) // List.apply(1, 2, 3) list(1) // list.apply(1) // + メソッドの呼び出し。ドットはスペースに置換可能、引数の() も省略可能 1 + 2 // 1.+(2) // 全ての文が式であり、値を返す val result = if (x > 10) "large" else "small" Scala はいいぞ 5
  4. 雑談: Scala の好きなところ 構文の例外が少なく、一貫したルールの上に成り立っている。 Rust の場合 let list = vec![Some(1),

    None, Some(2)]; // パターンマッチは match キーワードで開始する let matched = match &list[..] { [head, ..] => head, [] => None, } // map メソッドに渡す場合、クロージャの中で match を使う。 let mapped: Vec<i32> = list.into_iter().map(|x| match x { Some(v) => v * 2, None => 0, }).collect(); Scala はいいぞ 6
  5. 雑談: Scala の好きなところ 構文の例外が少なく、一貫したルールの上に成り立っている。 Scala の場合 val list = List(Some(1),

    None, Some(2)) // パターンマッチ(メソッド呼び出しではないが) val matched = list match { case head :: tail => head case Nil => None } // match とメソッド呼び出しが同じ見た目 val mapped = list map { case Some(v) => v * 2 case None => 0 } Scala はいいぞ 7
  6. 本題: Scala のいいところ flatMap の話をします 値を引き継いで処理しながら、値だけではなく構造に干渉できる仕組み // M[A] のメソッドとしてのflatMap def

    flatMap[B](f: A => M[B]): M[B] // List の場合 // 初めは長さ3 のリストだが、長さ6 のリストになった List(1, 2, 3).flatMap(i => List(i, i*2)) // Option の場合 (Some / None) // 初めはSome= 値があるが、途中でNone= 値なしになった Some(1).flatMap(i => None).flatMap(i => Some(i.toString)) // 結果は None // Either の場合 (Right / Left) // 初めはRight= 成功だが、途中でLeft= 失敗になった Right(1).flatMap(i => Left("err")).flatMap(i => Right(i*2)) // 結果は Left("err") Scala はいいぞ 10
  7. 本題: Scala のいいところ for 式: 連続したflatMap をフラットに書ける // flatMap が連続するとネストがつらいよ

    val manager1: Option[Manager] = findUser("id-123").flatMap { user => findDepartment(user.deptId).flatMap { dept => findManager(dept.managerId).map { manager => manager } } } // for 式を使った、正常系だけが縦に並ぶ仕様書のような記述 val manager2: Option[Manager] = for { user <- findUser("id-123") dept <- findDepartment(user.deptId) // flatMap manager <- findManager(dept.managerId) // flatMap } yield manager // map Scala はいいぞ 11
  8. 本題: Scala のいいところ(ZIO ) flatMap 、あります! // 実行時にR を要求して //

    失敗の場合はE を返し // 成功の場合はA を返却する // ノンブロッキングな軽量スレッドで実行される関数オブジェクト val program: ZIO[R, E, A] // Option, Either, Future もお手軽にZIO として扱えます val fromOption = ZIO.fromOption(Some("ZIO")) val fromEither = ZIO.fromEither(Right("ZIO")) val fromFuture = ZIO.fromFuture(implicit ec => scala.concurrent.Future("ZIO")) Scala はいいぞ 13
  9. 本題: Scala のいいところ(ZIO ) // 複数のZIO を定義する def getUser(id: String):

    ZIO[Database, DBError, User] = ??? def getTasks(user: User): ZIO[TaskApi, ApiError, List[Task]] = ??? // ZIO を合成する def getActiveUserTasks(userId: String): ZIO[Database & TaskApi, DBError | ApiError, List[Task]] = for { user <- getUser(userId) tasks <- getTasks(user) } yield tasks // 全てのZIO のR, E が合わさったZIO が返却される // ZIO を実行する def executeProgram() = { val runnable: ZIO[Any, DBError | ApiError, List[Task]] = getActiveUserTasks("id-123") .provide(Database.instance, TaskApi.instance) .catchAll { case dbError: DBError => ??? case apiError: ApiError => ??? } Unsafe.unsafe { implicit unsafe => Runtime.default.unsafe.run(runnable).getOrThrowFiberFailure() } } Scala はいいぞ 14
  10. 比べてみよう: Typescript Typescript の場合 class TaskService { constructor(private db: DB,

    private api: Api) {} async getTasks(userId: string) { const user = await this.db.findUser(userId); if (!user) throw new UserNotFound(); try { return await withRetry( () => withTimeout(this.api.fetchTasks(user.id), 5000), 3 ); } catch (e: unknown) { if (e instanceof TimeoutError) throw e; throw new FetchError(e instanceof Error ? e.message : ''); } } Scala はいいぞ 16
  11. 比べてみよう: ZIO Scala の場合 def getTasks(userId: String) = for {

    db <- ZIO.service[DB] // ZIO[DB, Nothing, DB] api <- ZIO.service[Api] // ZIO[DB & Api, Nothing, Api] // ZIO[DB & Api, DBError | UserNotFound, User] user <- db.findUser(userId).someOrFail(UserNotFound()) // ZIO[DB & Api, DBError | UserNotFound | FetchError | TimeoutError, List[Task]] tasks <- api.fetchTasks(user.id) .mapError(e => FetchError(e.getMessage)) .timeoutFail(TimeoutError())(5.seconds) .retry(Schedule.recurs(3)) } yield tasks Scala はいいぞ 17