怖い(?)と思われてるものを真面目に話そう!
怖い人達(?)の話
@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
関数の説明のライブコーディング?
おわり。ありがとうございました