6. Scala利用の文脈
Object-Functional
Analysis and Design
Object-Functional
Programming
Service Platform as-a-Service
要求
Cloud Service
プログラム カスタマイズ
モデル
Model
Summay Model
要求
Apparel Cloud
Service
Regular Model
WireFrame
(+ Usage)
Mindmap Model
API Usage List
Use case Model
Domain Model
プログラム
(開発)
プログラム
(自動生成)
カスタマイズ
Service Description
参考: Everforthのモデル体系
http://modegramming.blogspot.jp/2015/04/ofadeverforth.html
17. 代数的構造デザインパターン
• 半群 (semigroup)
• モノイド (monoid)
• 群 (group)
結合律律 (associative law)
• 可換半群
• 可換モノイド
• 可換群(アーベル群)
可換律律 (commutative law)
• 環 (ring)
• 体 (field)
分配律律 (distributive law)
(a + b) + c = a + (b + c)
a + b = b + a
a * (b + c) = a * b + a * c
21. モナド
• 計算機科学におけるモナド(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)
• ⾮非常に難しい概念念
• 使うのは(慣れれば)それほど難しくない
• モダンな関数型プログラミングの中核概念念
28. Functor, Applicative Functor, Monad
⾮非公式理理解
Functor
Applicative Functor
Monad
F.point(x).map(f).map(g).map(h)
(A.point(x) |@| A.point(y) |@| A.point(z))(i(_, _, _))
f g h
f
f
g
g
h
h
i
x
x
y
z
M.point(x).flatMap(f).flatMap(g).flatMap(h)
for {
a <- M.point(x)
b <- f(a)
c <- g(b)
d <- h(c)
} yield d
^^(A.point(x), A.point(y), A.point(z))(i(_, _, _))
x
Option(1).map(f).map(g).map(h)
(Option(1) |@| Option(2) |@| Option(3))(i(_, _, _))
Option(1).flatMap(f).flatMap(g).flatMap(h)
30. 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向けに⽤用意
• 型クラス
• 純粋関数型データ構造
• Haskellで実績のある機能群をScalaで実現
31. Monadicプログラミングの効⽤用
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) !
} !
}!
Java⾵風
36. 基本形
def bigCalc(n: Int): String = {
val a = calcString(n)
val b = calcInt(n)
val c = calcFloat(n)
finalCalc(a, b, c)
}
bigCalc (3003 ms): 1000-1000-1000.0
> go(“bigCalc”)(bigCalc(1000))
37. Optionモナド
def bigCalcO(n: Int): Option[String] = {
for {
a <- Option(calcString(n))
b <- Option(calcInt(n))
c <- Option(calcFloat(n))
} yield finalCalc(a, b, c)
}
Monad
f g h
x
bigCalcO (3005 ms): 1000-1000-1000.0
> go(“bigCalcO”)(bigCalcO(1000))
for式(for ... yield)でmonadicな
パイプラインを構築
参考: Scala Tips/Option Index
http://modegramming.blogspot.jp/2012/02/scala-tips-option-index.html
38. Optionモナド
Monadic関数版
def calcStringO(n: Int): Option[String] = {
Option(calcString(n))
}
def calcIntO(n: Int): Option[Int] = {
Option(calcInt(n))
}
def calcFloatO(n: Int): Option[Float] = {
Option(calcFloat(n))
} def bigCalcO2(n: Int): Option[String] = {
for {
a <- calcStringO(n)
b <- calcIntO(n)
c <- calcFloatO(n)
} yield finalCalc(a, b, c)
}
Monad
f g h
x
bigCalcO2 (3005 ms): 1000-1000-1000.0
> go(“bigCalcO2”)(Await.result(bigCalcO2(1000), 1.minute))
A->M[B]
モナディック関数
for式にモナディック
関数を組み合わせるの
がイディオム
39. Futureモナド
val executorService = Executors.newFixedThreadPool(10)
implicit val executionContext = ExecutionContext.fromExecutorService(executorService)
def bigCalcP(n: Int): Future[String] = {
for {
a <- Future(calcString(n))
b <- Future(calcInt(n))
c <- Future(calcFloat(n))
} yield finalCalc(a, b, c)
}
Monad
f g h
x
bigCalcP (3017 ms): 1000-1000-1000.0
> go(“bigCalcP”)(Await.result(bigCalcP(1000), 1.minute))
40. Futureモナド
改良良版
def bigCalcP2(n: Int): Future[String] = {
val fa = Future(calcString(n))
val fb = Future(calcInt(n))
val fc = Future(calcFloat(n))
for {
a <- fa
b <- fb
c <- fc
} yield finalCalc(a, b, c)
}
Monad
f g h
x
bigCalcP2 (1005 ms): 1000-1000-1000.0
> go(“bigCalcP2”)(Await.result(bigCalcP2(1000), 1.minute))
モナディック処理理の前
にFutuerを開始
41. Future Applicative
def bigCalcP3(n: Int): Future[String] = {
import scalaz._, Scalaz._
(Future(calcString(n)) |@| Future(calcInt(n)) |@| Future(calcFloat(n)))(finalCalc)
}
def bigCalcP31(n: Int): Future[String] = {
import scalaz._, Scalaz._
^^(Future(calcString(n)), Future(calcInt(n)), Future(calcFloat(n)))(finalCalc)
}
Applicative Functor
f
g
h
i
x
y
z
bigCalcP3 (1162 ms): 1000-1000-1000.0
bigCalcP31 (1004 ms): 1000-1000-1000.0
>go(“bigCalcP3”)(Await.result(bigCalcP3(1000), 1.minute))
> go(“bigCalcP31”)(Await.result(bigCalcP31(1000), 1.minute))
Applicativeを使うと綺
麗麗に記述できる
42. Future Applicative
改良良版
def bigCalcA[A[_]](n: Int)(implicit C: Applicative[A]): A[String] = {
^^(
C.point(calcString(n)),
C.point(calcInt(n)),
C.point(calcFloat(n))
)(finalCalc)
}
Applicative Functor
f
g
h
i
x
y
z
bigCalcAF (1003 ms): 1000-1000-1000.0
bigCalcAI (3001 ms): 1000-1000-1000.0
>go(“bigCalcAF”)(Await.result(bigCalcA[Future](1000), 1.minute))
> go(“bigCalcAI”)(bigCalcA[Id](1000), 1.minute))
型クラスを利利⽤用し任意
のApplicativeを使える
ように汎⽤用化
Applicativeのpointメソッド
はvirtual constructor
ロジック(機能要求)からApplicativeとして
パラメタ化した⾮非機能要求を分離離