【TsKaigi】「Step by Stepで学ぶ、ADT(代数的データ型)、モナドからEffect-TSまで」を聞きました

Step by Stepで学ぶ、ADT(代数的データ型)、モナドからEffect-TSまで

tskaigi.org

竹下義晃 様(@takezoux2)

レバレジーズ株式会社 / テクノロジー戦略室 室長

内容メモ

関数型と聞いてどんな印象がありますか?

  • すでに身近で使っている
    • Arrayのfilter, map, flatMap, reduceは関数型から取り入れられたもの
  • 関数型の概念も、根底には何かしらの課題があって、それを解決している

今回の説明範囲

  • ADT, Either, TaskEither, Effect-tsについて

サンプルコード

emailとpasswordでユーザー登録をおこない、完了メールを送る

普通に書くなら

function createUser(param) {
  if( !validateInput(param)) {
    throw
  }
  try {
    result = save(param)
  } catch {
    throw
  }
  sendRegisteredEmail(param.email)
}

→ 失敗成功のT/Fをどうするかが人による → 地味にif多い

これらをADTを取り入れていい感じにする

ADTを導入する

ADTとは?

直積型と直和型を組み合わせて表現される型

直積:{name: string, age: number} -> nameとageの直積

直和:"google" | "FaceBook" | "X"

validateInput

戻り値を Success| {type: "InvalidEmail", message: ""}

を返すようにする

→ 型定義だけでメソッドの挙動がわかるようになった

(感想メモ:失敗の理由が返ってくるの。シンプルな解決だけど強力だなぁ)

しかし、まだifは減っていない

Either

を導入する

Eitherとは、Either<Left, Right>の型定義を持つMethod

Rightに正しい状態を返す。

成功と失敗を型で表現することができるようになった書き方

usecaseの方では、isLeft(), isRight()の方で成功か失敗を判別すればいい

→ まだif文多い。ちょっと冗長になっている

pipeを導入する

これを導入することによって、if文がなくなった。

処理を分割して、組み合わせやすくなった。

しかし問題点として、型パズルやPromiseどうするの?という話がまだある。

PromiseとEitherが相性悪い

普通に書こうと思うと、コンパイルエラーになってしまう。そのため、TaskとTaskEitherを用いる。

Task<T>は処理を型で表現したMonad

実態は() => Promise<T>

これをすることで、PromiseもMonadに巻き込むことができた。しかし、型パズル感が増えた

Effect-TSを導入する

Effect Monadを中心としたライブラリ

Effect<Success, Error, Requirements>の型を持つ

Either, TaskEitherをEffectで置き換える

これをすると、Effectがすべての型を含んでいるので、型パズル間を減らすことができる。

generatorスタイルも使える→switchやif文を使った方がわかりやすいケースもEffectで対応することができる

効果

  • バグが減る
    • ロジックまで型で表現できて、コンパイラがチェックしてくれる
  • 拡張性、メンテナンス性UP
    • 処理をより小さく分割しやすい

感想

今回のStep by stepの流れの中で、関数型言語の良い部分について知ることができた。

自分が不勉強で、monadなどについてちゃんと理解できなかったので勉強しよう!

if文を減らすことができるのが感動的。試してみたくなった。