9
8

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 5 years have passed since last update.

implicit parameter や Reader でコンテキスト引き回し

Last updated at Posted at 2015-08-13

DB のセッションだったり、処理中の HTTP request だったり、何らかのコンテキストを引き回したいときに implicit parameter 使うことがある。

Context#x() が Int をとって Int を返すとすると、 implicit parameter で引き回すプログラムはこんなかんじになる。

// 適当な関数 f と g の定義
def f(i: Int)(implicit context: Context): Int = context.x(i)
def g(i: Int)(implicit context: Context): Int = f(i) * 2

// 呼び出し
implicit val myContext: Context = ???
val x = g(1)
val y = g(x)

呼び出し時に毎回 Context を引数に書かなくても良いのが良い所。

implicit を使わなずに普通の引数にすると呼び出し時に毎回コンテキストを渡すことになる。

// 適当な関数 f と g の定義
def f(i: Int, context: Context): Int = context.x(i)
def g(i: Int, context: Context): Int = f(i) * 2

// 呼び出し
val x = g(1, myContext)
val y = g(x, myContext)

scalaz.Reader の場合。

// 適当な関数 f と g の定義
def f(i: Int): Reader[Context, Int] =
  Reader { context => context.x(i) }
def g(i: Int): Reader[Context, Int] = f(i).map(_ * 2)

// 呼び出し
(for {
  x <- doSomething(1)
  y <- doSomething(x)
} yield y).run(myContext)

type alias を定義すればスッキリ見える。

type Work[A] = Reader[Context, A]
def f(i: Int): Work[Int] = Reader { context => context.x(i) }
def g(i: Int): Work[Int] = f(i).map(_ * 2)

f や g の = の前までは一番短い。
呼び出しでは暗黙的にコンテキストを渡すことは出来ない。for式などを使うことで、複数の Reader を組み合わせることができるので、最後 run するときだけ渡せば良い。呼び出し時に context を何度も書く必要はない。

暗黙的にコンテキストを渡す場合には複数ある implicit の探索箇所のいずれかにデフォルトコンテキストを忍ばせるなどができる。run 時に明示的に渡すのはそれはそれで気持ちが良い。

他のモナドと混ぜるときには ReaderT をつかうか、for などをネストするかになるのかな。すこしめんどい。

いままで implicit で引き回していたところを Reader を使うようにすれば、implicit は型クラスだけに使うべき派(?)になれるのかもしれない。

9
8
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
9
8

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?