scalazのコードリーディングしたメモ

- [Scalaz の Syntax という仕組みの解説 - scalaとか・・・](http://d.hatena.ne.jp/xuwei/20121217/1355687398)
- [ひなたねこ: Scalazのかきかた](http://basking-cat.blogspot.jp/2012/12/scalaz.html)

ここらへんのエントリ読んだんだけど、いまいち分からなかったのでscalazのコード読んだ。のをまとめる。
OptionとFunctorに絞って調べたけど、多分それ以外も同じだと思う。
実行環境はscala v2.10.3, scalaz v7.0.6。偶然手元でIntelliJで開いてたプロジェクトのバージョンがそうだっただけで特にこのバージョン特有の何かがあるわけではない。

# なぜsome(1)がSome(1)になるのか

```scala
import scalaz._
import Scalaz._
some(1) // Some(1)
```

定義元を調べると、ここ

```scala
  final def some[A](a: A): Option[A] = Some(a)
```

- https://github.com/scalaz/scalaz/blob/v7.0.6/core/src/main/scala/scalaz/std/Option.scala#L146

これは単純に`import Scalaz._`した時に


```scala
package scalaz

object Scalaz
  extends StateFunctions        // Functions related to the state monad
  with syntax.ToTypeClassOps    // syntax associated with type classes
  with syntax.ToDataOps         // syntax associated with Scalaz data structures
  with std.AllInstances         // Type class instances for the standard library types
  with std.AllFunctions         // Functions related to standard library types
  with syntax.std.ToAllStdOps   // syntax associated with standard library types
  with IdInstances              // Identity type and instances
```

- https://github.com/scalaz/scalaz/blob/v7.0.6/core/src/main/scala/scalaz/Scalaz.scala#L8

ここがimportされ、std.AllFunctions→OptionFunctionsとたどると`some`の定義元にたどり着く。

このような`XxxFunctions`traitはグローバル関数っぽく使う関数が定義されているらしい。

# 1.someがなぜSome(1)になるのか。

```scala
import scalaz._
import Scalaz._
1.some // Some(1)
```

これの仕組み。
この`.some`の定義元をIDEで調べると、ここになる

```scala
trait OptionIdOps[A] extends Ops[A] {
  def some: Option[A] = Some(self)
}
```

- https://github.com/scalaz/scalaz/blob/v7.0.6/core/src/main/scala/scalaz/syntax/std/OptionIdOps.scala#L4-L6

なぜこれが呼び出されるのか？
前節と同じようにScalaz→syntax.std.ToAllStdOps→ToOptionIdOpsの順でたどると

```scala
trait ToOptionIdOps {
  implicit def ToOptionIdOps[A](a: A) = new OptionIdOps[A] { def self = a }
}
```

- https://github.com/scalaz/scalaz/blob/v7.0.6/core/src/main/scala/scalaz/syntax/std/OptionIdOps.scala#L8-L10

ここにimplicit conversionが定義されており、`1`が`new OptionIdOps[Int] { def self = 1 }`に変換され、このオブジェクトが`some`メソッドを持ってるので`Some(1)`になる。

このような`XxxIdOps`はimplicit conversionを利用して既存の型に生やすメソッドを定義している模様[^1]。`ToXxxIdOps`がそのとき使うimplicit conversionを定義してる。多分OpsはOperationsの略。

[^1]: このようなテクニックをメソッド注入とかpimp my libraryとかenrich my libraryとか静的モンキーパッチとか言うらしい。

# なぜFunctor[Option].fpair(Option(1))がSome(1,1)になるのか
ここからが本番

```scala
import scalaz._
import Scalaz._
Functor[Option].fpair(Option(1)) // Some(1,1)
```

`Functor[Option]`は

```scala
object Functor {
  @inline def apply[F[_]](implicit F: Functor[F]): Functor[F] = F

  ////

  ////
}
```

- https://github.com/scalaz/scalaz/blob/v7.0.6/core/src/main/scala/scalaz/Functor.scala#L87

これの`apply`とimplicitパラメータを省略した形[^2]。なので、`F`が返る。この`F`は`Functor[Option]`型のimplicitパラメータで、

```scala
  implicit val optionInstance = new Traverse[Option] with MonadPlus[Option] with Each[Option] with Index[Option] with Length[Option] with Cozip[Option] with Zip[Option] with Unzip[Option] with IsEmpty[Option] {
略
```

- https://github.com/scalaz/scalaz/blob/v7.0.6/core/src/main/scala/scalaz/std/Option.scala#L11

これ。`Traverse`が`Functor`をmix-inしているので、`optionInstance`が`Functor[Option]`になる。これは今まで同様Scalaz→std.AllInstances→OptionInstancesの順にたどると辿り着く。

よって、`Functor[Option].fpair(Option(1))`は`optionInstance.fpair(Option(1))`になる。

で、Functor traitに定義されているfpair

```scala
  def fpair[A](fa: F[A]): F[(A, A)] = map(fa)(a => (a, a))
```

- https://github.com/scalaz/scalaz/blob/v7.0.6/core/src/main/scala/scalaz/Functor.scala#L40

が呼び出され、`Option(1)`を渡すと`Some(1,1)`になる。

[^2]: `Functor`とだけ書くと`Functor`オブジェクトを指すが、`Functor[Option]`のように型パラメータをつけると`apply`の省略形になる。最初これに気づかず混乱した。

# なぜimplicitly[Functor[Option]].fpair(Option(1))がSome(1,1)になるのか
ここらへんを調べると、以下の2つの書き方が出てくる。

```scala
Functor[Option].fpair(Option(1))
implicitly[Functor[Option]].fpair(Option(1))
```

これはどちらも前節で出てきた`optionsInstance`を取得しているだけ。前者のほうは`apply`の第一引数リストが`(implicit F: Functor[F])`になっていて`optionInstance`を取得していて、後者はこのimplicit parameterを直接取得している[^3]。あとは前節と同じ仕組み。

[^3]: implicitlyはscala.Predefにある関数でimplicitな値を取得する関数。

# なぜOption(1).fpairはSome(1,1)になるのか

```scala
import scalaz._
import Scalaz._
Option(1).fpair // Some(1,1)
```

Scalaz→ToTypeClassOps→ToFunctorOpsでたどると

```scala
  implicit def ToFunctorOps[F[_],A](v: F[A])(implicit F0: Functor[F]) =
    new FunctorOps[F,A] { def self = v; implicit def F: Functor[F] = F0 }
```

- https://github.com/scalaz/scalaz/blob/v7.0.6/core/src/main/scala/scalaz/syntax/FunctorSyntax.scala#L33-L34

このimplicit conversionが定義されている。今、`F`は`Option`, `A`は`Int`だ。
で、`implicit F0: Functor[F]`は既に見たとおり`optionInstance`だ。
なので、`Option(1).fpair`は`new FunctorOps[Option,Int] { def self = Option(1); implicit def F: Functor[Option] = optionInstance }.fpair`になる。
で、`fpair`の定義は

```scala
  final def fpair: F[(A, A)] = F.fpair(self)
```

- https://github.com/scalaz/scalaz/blob/v7.0.6/core/src/main/scala/scalaz/syntax/FunctorSyntax.scala#L17

になっていて、つまり`optionInstance.fpair(Option(1))`となる。これはもはや前節・前前節と同様なわけで、Some(1,1)になる。
このように`ToXxxOps`は`XxxOps`へのimplicit conversionを定義している模様。

# 型クラス
前節の仕組みはFunctor+Optionだったが、例えばFunctor+Listでも同様のことが出来る。

```
import scalaz._
import Scalaz._
List(1).fpair // List((1,1))
```

また、この時実行されるFunctorまわりのコードはOptionの時と同じだ。違うものは、Optionの時optionInstanceだったのが`listInstance`になるだけだ。

```
  implicit val listInstance = new Traverse[List] with MonadPlus[List] with Each[List] with Index[List] with Length[List] with Zip[List] with Unzip[List] with IsEmpty[List] {
略
```

- https://github.com/scalaz/scalaz/blob/v7.0.6/core/src/main/scala/scalaz/std/List.scala#L14

`fpair`のインタフェースを変えずに複数の型で動くようになっている。このようにimplicit conversionを駆使して多相性を実現するテクニックは、Haskellの型クラスの機能をエミュレートしているためscalaでも単に型クラスと言うらしい。
以下のページが分かりやすかった。

- [Scalaで型クラス入門 — still deeper](http://chopl.in/blog/2012/11/06/introduction-to-typeclass-with-scala.html)

# 参考
- [Scalaz の Syntax という仕組みの解説 - scalaとか・・・](http://d.hatena.ne.jp/xuwei/20121217/1355687398)
- [ひなたねこ: Scalazのかきかた](http://basking-cat.blogspot.jp/2012/12/scalaz.html)
- [独習 Scalaz — 13日目 (import ガイド)](http://eed3si9n.com/learning-scalaz/ja/day13.html)
- [こわくない型クラス](http://www.slideshare.net/kmizushima/ss-28707326)
- [型クラスペディア(The Typeclassopedia)](http://typeclassopedia.bitbucket.org/index-ja.html)