1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

【Cats Effect3】MonadCancel解説

Posted at

ライブラリを作成していていい感じに副作用なく非同期でIOを書きたくなったので改めてCatsEffectに入門したがドキュメントだけ見てもよくわからなかったので学習ついでにまとめることにした。
なので少し駆け足でゆるく描きます。

対象の読者

  • CatsEffect3のドキュメントが難しいよぉという方。

MonadCancelとは

CatsのMonadErrorを継承したCatsEffect3で提供されるUnqueClockを除く全ての型クラスの親となる型クラス。
機能としては名前の通り処理のキャンセルについての機能を提供する。

MonadErrorとの違い

一言で言うと回復可能かどうか。

/** MonadErrorはエラーから回復することができる。 */
val error = MonadError[IO,Throwable].raiseError[Int](new Throwable)
error.handleError(_ => 0).map(println)
// 0

/** handleErrorを使用してもキャンセルの状態が帰ってくる */
val canceled = MonadCancel[IO].canceled >> Applicative[IO].pure(1)
canceled.handleError(_ => 0).map(println)
// (出力されない)

/** 回復して値を返すのではなくキャンセル時のUnitを指定する */
canceled.onCancel(x: IO[Unit])

MonadCancel[F[_]].cancelはOption.Noneのような状態で、後続の処理は実行されない。
いくつか例:

IO.canceled     >> IO.println("a") //
IO.println("b") >> IO.canceled     // b

val c = IO.canceled >> IO.pure(10)
c.map(println)                                   //
c.map(println).onCancel(IO.println("canceled!")) // canceled!

uncancelable

では特定の箇所のみキャンセルを許容したい場合はどうするか。というときにuncancelableを使う。

MonadCancel[F[_]].uncancelable { poll => 
    ???
}

このpoll内の境界でのみキャンセルを許容する事が出来る。
例えば

IO.uncancelable { poll =>
    for {
        _ <- IO.canceled
        _ <- IO.println(1)
        _ <- poll(IO.canceled).onCancel(IO.println("canceled!"))
        _ <- IO.println(2)
    } yield ()
}
// 1
// canceled!

となる。
気を付けるべきポイントとしてはonCancelの定義場所なのだが、

IO.canceled >> IO.println("hello").onCancel(IO.println("canceled!"))
//

と書いても何も表示されない。
というのもCanceledの後続は評価されないのが原因なので、上記の IO.println("hello") に対してキャンセル時の処理を定義したい場合は

(IO.canceled >> IO.println("hello")).onCancel(IO.println("canceled!"))
// canceled!

と書く必要がある。

guarantee

日本語で言うと保証。
onCancel が try-catch文で言うところのcatchにあたるのならば、guaranteeはfinallyにあたる。
キャンセルされたかどうかに関係なく処理を実行する。

IO.canceled.guarantee(IO.println("canceled!")).map(println)
// canceled!
IO.pure(1).guarantee(IO.println("unit!")).map(println)
// unit!
// 1

怖いのは処理される順番。guaranteeで定義された処理が先に実行されるので要注意。

まとめ

CatsEffectではCatsの知識も必要になるのでお勉強が大変。
それとソースにもコメントで説明が書いてあるのでわからない時はソース見るのもいいカモ。

以上、ありがとうございました。

Twitter
GitHub

1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?