22. 代数的構造デザインパターン
結合律律 (associative law)
• 半群 (semigroup)
• モノイド (monoid)
• 群 (group)
可換律律 (commutative law)
• 可換半群
• 可換モノイド
• 可換群(アーベル群)
分配律律 (distributive law)
• 環 (ring)
• 体 (field)
(a + b) + c = a + (b + c)
a + b = b + a
a * (b + c) = a * b + a * c
25. A → B
• 関数の基本
• 型Aの値を型Bの値に置き換える (置き換えモデル,
substitution model)
• 副作⽤用はないので、A→Bの関数の外側にいかなる影響も
与えない (no side effect)
• 型Aの値が同じなら、いかなるタイミングで呼び出して
も型Bの同じ値が返る (参照透過性, referential
transparency)
• 論論理理学:ならば(imply)
• 圏論論:射(arrow, morphism)
• Readerモナド
• def f(x: A): B
26. A → B → C
• 引数が2つある関数
• 「A → B」の形の関数(引数が1つ)の合成で記述
• A → (B → C)
• Aを引数に取り「B→Cの関数」を返す関数
• def f(a: A, b: B): C
• def f(a: A)(b: B): C
• def f(a: A): B = C
• val f: A = B = C
27. A → A → A
• 「A → B → C」の特殊な形
• A, B, Cが同じ型
• ⼆二項演算⼦子
• 型Aがモノイドの候補
• f(x: A, y: A): A
• 1 + 1 → 2
• “abc” + “xyz” → “abcxyz”
• List(“abc”) ++ List(“xyz”) → List(“abc”, “xyz”)
30. 代数的データ型
• Algebraic data type
• 直積 (direct product)
• 論論理理学: ∧(論論理理積、かつ)
• Tuple
• Case class
• 直和 (direct sum)
• 論論理理学: ∨(論論理理和、または)
• Either
• sealed trait/abstract class + case class/case object
31. 代数的データ型
ケースクラスで直積を実現
case class Person(name: String, age: Int)
Case class Company(name: String, phone: String)
Eitherで直積の直和を実現
Either[Person, Company]
sealedトレイトで直積の直和
sealed trait Party
case class Person(name: String, age: Int) extends Party
case class Company(name: String, phone: String) extends Party
33. 型クラス
• In computer science, a type class is a type system
construct that supports ad hoc polymorphism. This
is achieved by adding constraints to type variables in
parametrically polymorphic types. (Wikipedia)
• ⾮非公式理理解
• OOPのクラスの関数型バージョン
• OOPでも有効に使⽤用できる
• OOPのクラスとの違い
• コンパイル時にポリモーフィズムが解決される
• 任意のクラスに後付けで設定できる
• ⽂文脈によって切切り替えて使⽤用できる
• Scalaでは暗黙パラメタで実現
34. 型クラスの使⽤用例例
case class Average(total: Double, count: Int) {
def value = total / count
def +(rhs: Average) = Average(total + rhs.total, count + rhs.count)
}
object Average {
implicit object AverageMonoid extends Monoid[Average] {
def append(lhs: Average, rhs: = Average) = lhs + rhs
def zero = Average(0, 0)
}
}
35. object MonoidSample {
import Average.AverageMonoid
def concatenate[T: Monoid](xs: Vector[T]): T = {
val C = implicitly[Monoid[T]]
xs.foldLeft(C.zero)((z, x) = z |+| x)
}
def sample {
val a: Int = concatenate(Vector(1, 2, 3))
assert(a == 6)
val b: Average = concatenate[Average](Vector(
Average(1.0, 1), Average(2.0, 2), Average(3.0, 3)))
assert(b == Average(6.0, 6))
}
def main(args: Array[String]) {
sample
}
}
37. モナド
• 計算機科学におけるモナド(Monads)とは、計算機科学者の
Eugenio Moggiによって提案されたモジュール性を持たせた
表⽰示的意味論論の枠組みを⾔言う。プログラムとはクライスリ圏
の射である(a program is an arrow of a Kleisli category)、
という要請から合成規則としてクライスリトリプル(Kleisli
triple)というモナドと等価なものが⽤用いられる。(Wikipedia)
• In functional programming, a monad is a structure that
represents computations defined as sequences of steps: a
type with a monad structure defines what it means to
chain operations, or nest functions of that type together.
This allows the programmer to build pipelines that
process data in steps, in which each action is decorated
with additional processing rules provided by the monad.
(Wikipedia)
• ⾮非常に難しい概念念
• 使うのは(なれれば)それほど難しくない
• モダンな関数型プログラミングの中核概念念
41. Scalaz
• https://github.com/scalaz/scalaz
• キャッチフレーズ
• 昔: Scalaz: Type Classes and Pure Functional Data
Structures for Scala
• 今: An extension to the core Scala library for functional
programming. http://typelevel.org
• 最新の関数型プログラミングを可能にする機能群を
Scala向けに⽤用意
• 型クラス
• 純粋関数型データ構造
42. Monadicプログラミングの効⽤用
Java⾵風
def validate(name: String, age: Int): ValidationNEL[Throwable, (String,
Int)] = {!
val a = validateName(name) !
val b = validateAge(age) !
if (a.isSuccess b.isSuccess) { !
val a1 = a.asInstanceOf[Success[NonEmptyList[Throwable], String]].a !
val b1 = b.asInstanceOf[Success[NonEmptyList[Throwable], Int]].a !
Success((a1, b1)) !
} else if (a.isSuccess) { !
b.asInstanceOf[Failure[NonEmptyList[Throwable], (String, Int)]] !
} else if (b.isSuccess) { !
a.asInstanceOf[Failure[NonEmptyList[Throwable], (String, Int)]] !
} else { !
val a1 = a.asInstanceOf[Failure[NonEmptyList[Throwable], String]].e !
val b1 = b.asInstanceOf[Failure[NonEmptyList[Throwable], Int]].e !
Failure(a1 |+| b1) !
} !
}!
43. Scala (関数型プログラミング)
def validate(name: String, age: Int):
ValidationNEL[Throwable, (String, Int)] = { !
validateName(name) match { !
case Success(a) = validateAge(age) match { !
case Success(b) = Success((a, b)) !
case Failure(e) = Failure(e) !
} !
case Failure(e1) = validateAge(age) match { !
case Success(b) = Failure(e1) !
case Failure(e2) = Failure(e1 |+| e2) !
} !
} !
} !
Scalaz (Monadicプログラミング)
def validate(name: String, age: Int):
ValidationNEL[Throwable, (String, Int)] = { !
(validateName(name) ⊛ validateAge(age))((_, _)) !
}!
URL: http://modegramming.blogspot.jp/2012/04/
scala-tips-validation-10-applicative.html
46. Stateモナドの使⽤用例例
case class Stack(stack: List[Int])
def main(args: Array[String]) {
sample
}
def sample {
val stack = Stack(Nil)
val r = pipe.run(stack)
assert(r == (Stack(List(10)), 10), s$r)
}
47. val pipe: State[Stack, Int] = {
for {
a - push(10)
b - push(a)
c - pop
} yield c
}
def push(x: Int) = State[Stack, Int] { s =
(Stack(x :: s.stack), x)
}
def pop = State[Stack, Int] { s =
s.stack match {
case x :: xs = (Stack(xs), x)
case Nil = ???
}
}
50. Future case class Site(uri: String, page: String)
def largestSite: Future[Site] = {
for {
a - future(getSite(http://www.yahoo.com))
b - future(getSite(http://www.amazon.com))
c - future(getSite(http://www.google.com))
} yield {
Vector(a, b, c).maxBy(_.page.length)
}
}
def getSite(uri: String): Site = {
Site(uri, new URL(uri).asInput.string)
}
def main(args: Array[String]) {
largestSite.onSuccess {
case site = println(swin = ${site.uri})
}
}
51. RxJava - Scala
• Functional Reactive Programming
• https://github.com/Netflix/RxJava
• http://techblog.netflix.com/2013/02/rxjava-netflix-api.html
def simpleComposition() {
// fetch an asynchronous ObservableString
// that emits 75 Strings of 'anotherValue_#'
customObservableNonBlocking()
// skip the first 10
.skip(10)
// take the next 5
.take(5)
// transform each String with the provided function
.map({ stringValue - return stringValue + _transformed})
// subscribe to the sequence and print each transformed String
.subscribe({ println onNext = + it})
}
52. scalaz stream
• Functional Reactive Programming
• https://www.chrisstucchio.com/blog/2014/
scalaz_streaming_tutorial.html
for {
bag - resource.managed(new FileBag())
bag2 - resource.managed(new FileBag())
bag3 - resource.managed(new FileBag())
} {
Process.constant(4096).through(io.chunkR(new URL(http://scala-lang.
org/).openStream)).to(bag.chunkW).run.run
bag.chunksR(4096).to(bag2.chunkW).run.run
bag2.linesR.map(_ + n).pipe(text.utf8Encode).to(bag3.chunkW).run.run
bag.size should be (bag2.size)
bag.size should be (bag3.size)
}
53. Spark
• RDD (Resilient Distributed Dataset)
• http://www.cs.berkeley.edu/~pwendell/strataconf/api/core/
spark/RDD.html
scala val textFile = sc.textFile(README.md)
textFile: spark.RDD[String] = spark.MappedRDD@2ee9b6e3
scala val linesWithSpark = textFile.filter(line =
line.contains(Spark))
linesWithSpark: spark.RDD[String] = spark.FilteredRDD@7dd4af09
scala textFile.filter(line = line.contains(Spark)).count() // How
many lines contain Spark?
res3: Long = 15