怖い(?)と思われてるものを真面目に話そう!
怖い人達(?)の話
@adelbertchang @larsr_h @xuwei_k Kenji is rock and rolling like a champ.
— Tony Morris (@dibblego) September 22, 2013
((((;゚Д゚))))ガクガクブルブル
Scalazやモナドの話
http://leifwarner.net/scalaz.svg この図は7.0.x系なので、7.1.xと少し違う
モナド!
モナド!
モナド!
モナドを避けているから、必要以上に怖く感じるのでは? モナドを理解してしまおう!
では、モナドとはなにか?
単なる型クラスの1つ
では、型クラスとは?
型クラスの定義 https://github.com/scala/scala/blob/v2.10.3/src/library/scala/math/Ordering.scala
trait Ordering[T]{
def compare(x: T, y: T): Int
}
上記のコードは色々省略してあります
型クラスのインスタンスの定義
https://github.com/scala/scala/blob/v2.10.3/src/library/scala/math/Ordering.scala#L250-L256
trait IntOrdering extends Ordering[Int] {
def compare(x: Int, y: Int) =
if (x < y) -1
else if (x == y) 0
else 1
}
implicit object Int extends IntOrdering
型クラスを使う側 https://github.com/scala/scala/blob/v2.10.3/src/library/scala/collection/TraversableOnce.scala#L214
def max[B >: A](implicit cmp: Ordering[B]): A
ほとんどの型クラスには「満たすべき法則がある」
法則とは?
equalsとhashCodeが特定の法則を満たさないといけないようなもの
Orderingならば、a > b かつ b > c ならば a > c など(推移律)
モナドの型クラスの定義
trait Monad[F[_]]{
def bind[A, B](fa: F[A])(f: A => F[B]): F[B]
def point[A](a: => A): F[A]
}
モナド則とは
return a >>= k == k a
m >>= return == m
m >>= (\x -> k x >>= h) == (m >>= k) >>= h
Haskellではあれなので、Scalazにおける例
モナド則その1
https://github.com/scalaz/scalaz/blob/v7.1.0-M4/core/src/main/scala/scalaz/Monad.scala#L71
def leftIdentity[A, B](a: A, f: A => F[B])(implicit FB: Equal[F[B]]): Boolean =
FB.equal(bind(point(a))(f), f(a))
モナド則その2
https://github.com/scalaz/scalaz/blob/v7.1.0-M4/core/src/main/scala/scalaz/Monad.scala#L73
def rightIdentity[A](a: F[A])(implicit FA: Equal[F[A]]): Boolean =
FA.equal(bind(a)(point(_: A)), a)
モナド則その3
https://github.com/scalaz/scalaz/blob/v7.1.0-M4/core/src/main/scala/scalaz/Bind.scala#L40-L41
def associativeBind[A, B, C](fa: F[A], f: A => F[B], g: B => F[C])(implicit FC: Equal[F[C]]): Boolean =
FC.equal(bind(bind(fa)(f))(g), bind(fa)((a: A) => bind(f(a))(g)))
もうみなさん、モナドを理解しましたね!
提案:
ということと
を分けて考えよう!
型クラスの継承関係
Monadの親の型クラス
InvariantFunctor (これはめったに使わないので忘れてもいいです)
Functor
Apply
Bind
Applicative
ScalazとHaskellと違い
Functor, Applicative, Monad の3つのみ
Apply, Bind がScalazにはある
Semigroupはない
Apply ならば、必ず Functor になる
Applicative ならば、必ず Apply になる
Bind ならば、必ず Apply になる
Monad ならば、必ず Applicative になる
Monad ならば、必ず Bind になる
Bind にはなるが Monad にはならない例が存在する(Mapなど)
Applicaive にはなるが Monad にはならない例( scalaz.Validation など)
よくある誤解
マサカリが飛んでくるかもしれません?
scalaz.Monadを含めた様々な型クラスを使ったり、新たに定義する場合には色々な知識が必要
また、Monad と同時に、それらと関連する型クラスである Functor なども同時に理解するようにしたほうがいい
Scalazを使いたくてもどこから使っていいかわからない人向けの話
scalaz.Validation
Applicative#sequence
なぜ Validation がScalaz初心者にオススメなのか?
Semigroup も関連する
NonEmptyList の利点が生かせる
scalaz.Validation と同じような実装
JsResult
https://github.com/playframework/playframework/blob/2.2.1/framework/src/play-json/src/main/scala/play/api/libs/json/JsResult.scala
Or(scalatestの人が作ったもの)
https://github.com/scalatest/scalatest/blob/release-2.0-for-scala-2.10/src/main/scala/org/scalautils/Or.scala#L581
Scala2.10から入ったFutureを使う場合
Option[Future[A]] を Future[Option[A]] にしたい
とかよくあるはず
Scalaz7.0.xの場合は、scala.concurrent.Futureの型クラスのインスタンスは入ってないので以下の設定が必要
libraryDependencies ++= Seq(
"org.typelevel" %% "scalaz-contrib-210" % "0.1.5",
"org.scalaz" %% "scalaz-core" % "7.0.5"
)
scalaVersion := "2.10.3"
import scala.concurrent.Future
import scalaz._
import Scalaz._
import scalaz.contrib.std.scalaFuture._ // 7.0.xの場合
import scalaz.std.scalaFuture._ // 7.1.0-M4の場合
import scala.concurrent.Future
import scala.concurrent.ExecutionContext.Implicits.global
Option(Future(1)).sequence // Future(Option(1))
A[B[C]]
という型のオブジェクトがあったとき、以下のどちらかであれば
A[B[C]] から B[A[C]] に変換できる
Validation や Applicativeのsequence関数の説明のライブコーディング?
おわり。ありがとうございました