Loan パターンのネストは継続モナドでシュッと解決できるよという話


先日見かけた [Closeモナド](http://qiita.com/yyu/items/b83f079381e47c65ce0e) についての言及になります

## この記事の概要

長くなりそうなので最初にまとめです

* `Close` モナドにはいくつかの問題があります
* それらの問題は既存の継続モナドによって解決できます
* リソース管理のために新たなモナドを考案する必要はありません

## Close モナドが抱える問題

動作の問題

* `run` を二回以上呼べません
  * リソースがインスタンス変数として保持されているためです
  * 言い換えると `map` や `flatMap` 自体に副作用があります

コードの問題

* `Close[R, A]` の `A` にアクセスするための手段が `map` しかありません
  * 副作用が目的の処理であっても `map` が必要になってしまいます
* クラス内にリソースを閉じるための `try-finally` が二回書かれています
  * DRY に書きたいですね

## 継続モナドの導入

まずは最も簡潔な（と思われる）実装を先に載せておきます

```scala
package continuation

class Continue0[+A] private(callback: (A => Unit) => Unit) {

  def map[B](f: A => B): Continue0[B] = Continue0 {
    g => apply(f andThen g)
  }
  def flatMap[B](f: A => Continue0[B]): Continue0[B] = Continue0 {
    g => apply(a => f(a) apply g)
  }
  def apply(f: A => Unit): Unit = callback(f)

  def run(): Unit = callback(_ => ())
}
object Continue0 {
  def apply[A](f: (A => Unit) => Unit): Continue0[A] = {
    new Continue0(f)
  }
  def from[A](a: A): Continue0[A] = {
    new Continue0[A](f => f(a))
  }
}
```

呼び出し側のコードはこんな感じです

```scala
  def sample0() = {
    val continue = for {
      x1 <- Continue0 from 1
      x2 <- Continue0 from 2
      x3 <- Continue0 from 3
    } yield {
      x1 - x2 - x3
    }
    continue { n =>
      println(n)// -4
    }
  }
```

`for-yield` を展開してみましょう。綺麗なネストの出現を確認できます

```scala
  def sample1() = {
    val continue =
      Continue0 from 1 flatMap { x1 =>
        Continue0 from 2 flatMap { x2 =>
          Continue0 from 3 map { x3 =>
            x1 - x2 - x3
          }
        }
      }
    continue { n =>
      println(n)// -4
    }
  }
```

なんとなく形が見えてきましたね

## 継続モナドを利用して Close を実装する

といっても、コールバック関数を実行してリソースを閉じるだけです

```scala
package continuation

// Closer は元記事と同じ
import close.Closer

object Close {
  def apply[A: Closer](res: => A): Continue0[A] =
    Continue0 { callback =>
      val target = res
      try callback(target)
      finally implicitly[Closer[A]] close target
    }
}
```

念のため使用例も見てみましょう

```scala
  def main(args: Array[String]): Unit = {
    implicit def closer[R <: Closeable]: Closer[R] = Closer { x =>
      println(s"close: ${x.toString}")
      x.close()
    }
    val a = for {
      in     <- Close(new FileInputStream(getClass.getResource("/source.txt").getPath))
      reader <- Close(new InputStreamReader(in, "UTF-8"))
      buff   <- Close(new BufferedReader(reader))
      out    <- Close(new FileOutputStream("dest.txt"))
      writer <- Close(new OutputStreamWriter(out, "UTF-8"))
    } yield {
      println("[begin]")

      var line = buff.readLine()
      while (line != null) {
        println(line)

        writer.write(line + "\n")
        line = buff.readLine()
      }
      println("[end]")
    }
    a.run()
    a.run() // 二回目
  }
```

問題なさそうです。`run` も無事に二回呼べています。

```
[begin]
This
is
a
pen
[end]
close: java.io.OutputStreamWriter@400f2b73
close: java.io.FileOutputStream@13150587
close: java.io.BufferedReader@33ddbb85
close: java.io.InputStreamReader@122c984a
close: java.io.FileInputStream@2bc16dcf
[begin]
This
is
a
pen
[end]
close: java.io.OutputStreamWriter@10436c0d
close: java.io.FileOutputStream@4e1cec13
close: java.io.BufferedReader@3804d352
close: java.io.InputStreamReader@188b6e88
close: java.io.FileInputStream@13234a90
```

もう `for-yield` の最後の値を得るために `map` を呼ぶ必要もありません

```scala
    val foo = for {
      in     <- Close(new FileInputStream(getClass.getResource("/source.txt").getPath))
      reader <- Close(new InputStreamReader(in, "UTF-8"))
      buff   <- Close(new BufferedReader(reader))
      out    <- Close(new FileOutputStream("dest.txt"))
      writer <- Close(new OutputStreamWriter(out, "UTF-8"))
    } yield {
      "hello"
    }
    foo {
      message => println(message) // hello
    }
```

これで `Close` 自体のリファクタは終わりです。おつかれさまでした。

## 継続モナドを改善してコールバック関数を不要にする

簡単のため省きましたが、前述の継続モナドにはまだ不自然な i/f が残っています。

```scala
class Continue0[+A] private(callback: (A => Unit) => Unit) {
```

`(A => Unit) => (Unit)` の `Unit` って何だよ！そこの制限を外せば値を直接返せるじゃん！って思いますよね。思わなかったら今から思ってください。

しかしながら、ここで何も考えずに愚直に型パラメータを導入しても :

```scala
package continuation

class Continue1[R, +A] private(callback: (A => R) => R) {

  def map[B](f: A => B): Continue1[R, B] = Continue1 {
    g => apply(f andThen g)
  }
  def flatMap[B](f: A => Continue1[R, B]): Continue1[R, B] = Continue1 {
    g => apply(a => f(a) apply g)
  }
  def apply(f: A => R): R = callback(f)

  /*
  def run(): Unit = callback(_ => ())

  [error]  found   : Unit
  [error]  required: R
  [error]   def run(): Unit = callback(_ => ())
  [error]                                   ^
   */
}
```

`run` で上記のように叱られます。
`callback` の実行でしか必要のないはずの型 `R` をクラスに保持させているのが原因ですね。

ということで、多相の `apply` を得るために `callback` に専用の型を与えてしまいましょう。

```scala
package continuation

trait Callback[A] {
  def apply[R](f: A => R): R
}
class Continue[+A] private(callback: Callback[A]) {

  def map[B](f: A => B): Continue[B] =
    Continue apply new Callback[B] {
      override def apply[R](g: B => R): R = {
        callback(f andThen g)
      }
    }
  def flatMap[B](f: A => Continue[B]): Continue[B] =
    Continue apply new Callback[B] {
      override def apply[R](g: B => R): R = {
        callback(a => f(a) apply g)
      }
    }
  def apply[R](f: A => R): R = callback(f)
  def run(): A = apply(identity)
}
object Continue {
  def apply[A](f: Callback[A]): Continue[A] = {
    new Continue(f)
  }
  def from[A](a: A): Continue[A] = {
    Continue apply new Callback[A] {
      override def apply[R](f: A => R): R = f(a)
    }
  }
}
```

`Callback` は `Continue` で表現できることが分かったのでまとめます :

```scala
trait Continue[A] {
  self =>
  def map[B](f: A => B): Continue[B] = new Continue[B] {
    override def apply[R](g: B => R): R = self(f andThen g)
  }
  def flatMap[B](f: A => Continue[B]): Continue[B] = new Continue[B] {
    override def apply[R](g: B => R): R = self(a => f(a) apply g)
  }
  def apply[R](f: A => R): R
  def run(): A = apply(identity)
}

object Continue {
  def from[A](a: A): Continue[A] = {
    new Continue[A] {
      override def apply[R](f: A => R): R = f(a)
    }
  }
}
```

`Close` も少しゴツい実装に変わりますが… :

```scala
object Close {
  def apply[A: Closer](res: => A): Continue[A] =
    new Continue[A] {
      override def apply[R](f: A => R): R = {
        val target = res
        try f(target)
        finally implicitly[Closer[A]] close target
      }
    }
}
``` 

この変更によって直接 `run` が `A` の値を返せるようになります。
もうコールバック関数の存在すら意識する必要はありません。やった！

```scala
    val foo = for {
      in     <- Close(new FileInputStream(getClass.getResource("/source.txt").getPath))
      reader <- Close(new InputStreamReader(in, "UTF-8"))
      buff   <- Close(new BufferedReader(reader))
      out    <- Close(new FileOutputStream("dest.txt"))
      writer <- Close(new OutputStreamWriter(out, "UTF-8"))
    } yield {
      ...
      "hello"
    }
    println(foo.run()) // "hello"
```

これで一通りの i/f 改善も終わりです。今度こそおつかれさまでした。

## 参考リンク

* [Continuation monad in Scala](http://blog.tmorris.net/posts/continuation-monad-in-scala/)
    * Tonny Morris さんによる記事です
        * 投稿は 2008 年ですが概念は今でも変わっていません
        * 処理を分岐させる callcc 実装がとてもおもしろいです