SlideShare a Scribd company logo
実務者のための!
かんたんScalaz
2014年年7⽉月7⽇日
Everforth
浅海智晴
シリーズ
•  テーマ
•  クラウドアプリケーション開発技術の導⼊入
•  今後の予定
•  実務者のためのかんたんScalaプログラミング
•  実務者のためのかんたんScala⼊入出⼒力力プログラミング
•  実務者のためのかんたんScala設計
•  実務者のためのかんたんオブジェクト指向分析/設計
•  実務者のためのかんたん業務分析
今⽇日のテーマ
•  Monadicプログラミングの認知
•  概要、必要性
•  Scalaz導⼊入の⼊入り⼝口
•  必要最⼩小限の知識識&具体的な便便利利さ
•  Scalazの便便利利機能
•  Monoid
•  関数型プログラミングのパワーを知る
•  実作業にすぐに適⽤用可
⽂文脈
アジェンダ
⽂文脈
関数型プログラミング
Object Functional
Programming
Scalaz
新しい現実
•  メニーコア、⼤大容量量メモリ、SSD
•  インメモリデータベース
•  並列列プログラミング
ハードウェア
•  クラウド・サービス、スマート・デバイス
•  故障、遅延
•  ⼤大規模データ、⼤大規模演算
•  ⾼高頻度度イベント、ストリーミング
•  ⾮非同期、並列列、分散
•  NoSQL
クラウド・プラットフォーム
OFADの要素技術/関連技術
OFADOOAD
OFP
クラウド  
コンピュー
ティング
アジャイル
開発
UCD/UX
Scala
計算機科学
DSL
DDD
DCI
CQRS
EIP
EDA
はセッションで触れる技術
アプリケーションの階層と役割
•  DSLの作法に従ってビジネスロ
ジックを記述
•  OO、関数型のスキルは最低限
アプリケー
ション
•  フレームワークを簡単に使⽤用する
ための専⽤用⾔言語
•  OO、関数型の⾼高度度なスキル
DSL
•  ドメインの共通処理理を記述
•  OO、関数型の⾼高度度なスキル
フレーム
ワーク
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向けに⽤用意
•  型クラス
•  純粋関数型データ構造
関数型プログラミング
関数型⾔言語とは
•  ⾼高階関数を扱える。
•  関数を値として扱える。
•  関数の引数と返却値に関数を渡せる。
•  関数リテラル(クロージャ)が記述できる。
•  数学(ラムダ計算、数理理論論理理学、圏論論など)的にプログラ
ムを記述できる。
関数型⾔言語の系譜
元祖関数型⾔言語
• pure Lisp
• ラムダ計算
伝統的関数型
⾔言語
• Lisp, ML, OCaml
• ラムダ計算
• ⼿手続き、オブジェ
クト指向で補完
• 抽象データ型
• Subtype
polymorphism
新世代関数型
⾔言語
• Haskell
• Scala(+scalaz)
• ラムダ計算
• 代数、圏論論
• 型クラス
• 代数データ型、
モナド
• Parametric
polymorphism
浅海私⾒見見。
20年年ほどの空⽩白の後の⾒見見え⽅方、
あるいはOOプログラマが後追い
で調べたときの⾒見見え⽅方と考えて
ください。
関数型⾔言語の⻑⾧長所と短所
•  ⾼高階関数を使った技が使える
•  List, 関数合成(コンビネータ)など
•  定理理と証明
•  証明された(動作保証された)定理理(関数)を積み上げてプログラ
ムを記述できる  (← 多少理理想論論も⼊入ってます)
⻑⾧長所
•  関数実⾏行行のオーバーヘッド
•  関数オブジェクト
•  メモリを⼤大量量に消費する
•  関数オブジェクト
•  データの⼤大量量複写
•  スタックの使⽤用量量が読めない
•  再帰
短所
関数型⾔言語の技術マップ
代数的構造デザインパターン
•  半群 (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
圏論論デザインパターン
圏  (category)
• Hask圏 (Scala圏?)
• クライスリ圏  
(kleisli category)
射 (arrow,
morphism)
関⼿手  
(functor)
Applicative
functor
モナド  
(monad)
関数型を導⼊入する⽬目的
•  プログラミング効率率率
•  部品化・再利利⽤用
•  DSL
•  データフロー
•  並列列/並⾏行行プログラミング
•  ⼤大規模データ処理理
•  ストリーミングデータ処理理
•  イベント駆動プログラミング
関数型プログラミングの3つの技術
•  関数(「A → B」)を積み上げてプログラムを書く技術
•  パイプライン・プログラミング
•  直感的でそれほど難しいわけではない
•  モナドを使って関数をシステムと結びつける技術
•  難解
•  利利⽤用パターンは決まっているので、アプリケーション・プ
ログラマ的には、イディオムを覚えておけば⼗十分
•  オブジェクト指向分析・設計と結びつける技術
•  「実務者のためのかんたんオブジェクト指向分析・設計」
Scalazを実務に展開する戦略略
•  便便利利機能を活⽤用
•  Monoid
•  データ構造の導⼊入
•  Tree, NonEmptyList
•  EphemeralStream
•  Cord, Rope
•  Foldable, Traverse
•  Monadicプログラミング
•  並列列/並⾏行行プログラミング
•  ストリームプログラミング
A → B
•  関数の基本
•  型Aの値を型Bの値に置き換える (置き換えモデル,
substitution model)
•  副作⽤用はないので、A→Bの関数の外側にいかなる影響も
与えない (no side effect)
•  型Aの値が同じなら、いかなるタイミングで呼び出して
も型Bの同じ値が返る (参照透過性, referential
transparency)
•  圏論論:射(arrow, morphism)
•  論論理理学:ならば(imply)
•  def f(x: A): B
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
A → A → A
•  「A → B → C」の特殊な形
•  A, B, Cが同じ型
•  ⼆二項演算⼦子
•  f(x: A, y: A): A
•  1 + 1 → 2
•  “abc” + “xyz” → “abcxyz”
•  List(“abc”) ++ List(“xyz”) → List(“abc”, “xyz”)
A → M[B]
•  「A → B」の特殊な形
•  「B」の部分が「M[B]」となっている
•  Mはモナド、モナドMがBをくるんでいる形
•  モナドのbind演算で使⽤用する
•  def flatMap[A, B](f: A => List[B])
モナド
•  難解な概念念
•  http://ja.wikibooks.org/wiki/Haskell/%E5%9C%8F%E8%AB%96
•  ⾮非公式理理解
•  型安全汎⽤用フレームワーク基底クラス
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⾵風
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) !
} !
} !
} !
def validate(name: String, age: Int):
ValidationNEL[Throwable, (String, Int)] = { !
(validateName(name) ⊛ validateAge(age))((_, _)) !
}!
Scala (関数型プログラミング)
Scalaz (Monadicプログラミング)
URL: http://modegramming.blogspot.jp/2012/04/
scala-tips-validation-10-applicative.html
パイプライン・プログラミング
Arrowを⽤用いたデーターフロー
関数合成
モナドによる計算⽂文脈 (1)
モナドによる計算⽂文脈 (2)
パイプラインの構成部品
メソッド メソッド動作 動作イメージ コンテナ型 要素型 要素数
map コンテナ内の要素に
関数を適⽤用して新し
いコンテナに詰め直
す。
M[A]→M[B] 変わらない 変わる 同じ
filter コンテナ内の要素を
選別して新しコンテ
ナに詰め直す。
M[A]→M[A] 変わらない 変わらない 同じ/減る
fold コンテナをまるごと
別のオブジェクトに
変換する。
M[A]→N 変わる N/A N/A
reduce コンテナの内容を⼀一
つにまとめる。
M[A]→A 変わる N/A N/A
collect コンテナ内の要素に
部分関数を適⽤用して
選択と変換を⾏行行う。
M[A]→M[B] 変わらない 変わる 同じ/減る
flatMap コンテナ内の要素ご
とにコンテナを作成
する関数を適⽤用し最
後に⼀一つのコンテナ
にまとめる。
M[A]→M[B] 変わらない 変わる 同じ/増える/減
る
代数的データ型
•  Algebraic data type
•  直積の直和の総和
•  再帰構造
case class Person(name: String, age: Int)
Case class Company(name: String, phone: String)
ケースクラスで直積を実現
Either[Person, Company]
Eitherで直積の直和を実現
sealedトレイトで直積の直和の総和を実現
sealed trait Party
case class Person(name: String, age: Int) extends Party
case class Company(name: String, phone: String) extends Party
永続データ構造
•  Persistent data structure
•  変更更される際に変更更前のバージョンを常に保持するデータ構造で
ある。このようなデータ構造は、更更新の際に元のデータ構造を書
き換えるのではなく、新たなデータ構造を⽣生成すると考えられ、
イミュータブルなデータ構造の構築に利利⽤用可能である(Wikipedia)
並列列プログラミング
•  マルチスレッド  
•  共有状態 (shared mutability)
•  共有状態をロック ← 伝統的⽅方法
•  STM (Software Transactional Memory)
•  アクター
•  状態をアクターローカル(スレッドローカル)にする (isolating
mutability)
•  不不変オブジェクトによるメッセージで通信
•  関数プログラミング⽅方式
•  代数的データ型、永続データ構造
•  ⇒ 不不変オブジェクト
•  状態変更更ではなく、状態変更更命令令書を計算
•  イメージとしてはSQLの⽂文字列列を計算して作成する感じ
•  モナドのメカニズムを使って並列列処理理(+状態変更更命令令書)を
隠蔽
並列列プログラミング
def go[T](a: => T): (T, Long) = {
val start = System.currentTimeMillis
val r = a
val end = System.currentTimeMillis
(r, end - start)
}
val f = (x: Int) => {
Thread.sleep(x * 100)
x
}
scala> go(f(10))
res176: (Int, Long) = (10,1000)
scala> go {
| f(10)
| }
res253: (Int, Long) = (10,1001)
準備
時間を測る関数 テスト関数
scala> val fp = f.promise
fp: scalaz.Kleisli[scalaz.concurrent.Promise,Int,Int] =
scalaz.Kleislis$$anon$1@9edaab8
scala> go((1.some |@| 2.some |@| 3.some)(_ + _ + _).get)
res237: (Int, Long) = (6,1)
scala> go(f(1) + f(2) + f(3))
res212: (Int, Long) = (6,603)
scala> go((fp(1) |@| fp(2) |@| fp(3))(_ + _ + _).get)
res215: (Int, Long) = (6,302)
PromiseのKleisli
Applicative
scala> go(List(1, 2, 3).map(f).map(f))
res221: (List[Int], Long) = (List(1, 2, 3),1205)
scala> go(List(1, 2, 3).map(fp).map(_.flatMap(fp)).sequence.get)
res220: (List[Int], Long) = (List(1, 2, 3),602)
val fx = (x: Int) => {
val t = math.abs(x - 4)
Thread.sleep(t * 100)
x
}
val fxp = fx.promise
テスト関数
scala> go(List(1, 2, 3).map(f >>> fx))
res232: (List[Int], Long) = (List(1, 2, 3),1205)
scala> go(List(1, 2, 3).map(f).map(fx))
res223: (List[Int], Long) = (List(1, 2, 3),1205)
scala> go(List(1, 2, 3).map(fp >=> fxp).sequence.get)
res230: (List[Int], Long) = (List(1, 2, 3),402)
scala> go(List(1, 2, 3).map(fp).map(_.flatMap(fxp)).sequence.get)
res222: (List[Int], Long) = (List(1, 2, 3),402)
DSL
Anorm
Squeryl
Slick
SQL("""select name from coffees where price < 10.0""”)
from(coffees)(s =>
where(s.price < 10.0)
select(s))
coffees.filter(_.price < 10.0).map(_.name)
関数型プログラミングの秘密
•  不不変(immutable)なのに状態が持て、状態遷移を記述で
きる理理由
•  不不変(immutable)なのにデータ構造の変更更ができる理理由
•  副作⽤用なし(no side)なのに外部⼊入出⼒力力ができる理理由
scalaz stream
•  com.everforth.lib.util.FileBag
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)
}
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
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 Observable<String>
// 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})
}
Object  Functional  
Programming
OFP新三種の神器
•  mix-in
•  型安全のAOP的な運⽤用
トレイト  (trait)
•  計算⽂文脈をカプセル化する新しい⾔言語概念念
•  Monadicプログラミング
モナド  (monad)
•  型安全のダブルディスパッチ(?)
•  Scalaでは、⽂文脈、主体、客体の組でオブジェクトを束縛
型クラス  (type class)
オブジェクトと関数の連携(1)
オブジェクトと関数の連携(2)
関数と⼿手続き
•  関数は副作⽤用なし
•  副作⽤用があるものは「⼿手続き」
•  例例外も副作⽤用の⼀一種
•  厳密には例例外を発⽣生させる可能性のあるものは「⼿手続き」
•  プログラミングの⼿手間を考えて例例外は特別扱いしたい
•  本セッションでは「準関数」を導⼊入
要素 副作⽤用なし 参照透過性 例例外なし
関数 ◯ ◯ ◯
準関数 ◯ ◯ ×
⼿手続き ー ー ー
計算領領域を分ける
•  純粋関数型  :: 例例外は使⽤用せずモナドを⽤用いて例例外状態を
管理理する
•  準関数型A :: Tryモナド(準モナド)を使⽤用する
•  準関数型B :: 例例外を使⽤用する
•  ⼿手続き型  :: 普通のプログラミング
エラーハンドリング戦略略
•  オブジェクト指向⽅方式
•  例例外(Throwable)を使⽤用
•  try, catch, finally
•  関数型⽅方式
•  モナド系のコンテナを使⽤用する
種別 意味
モナド モナド機能を持っているコンテナ
準モナド モナド機能を持っているがモナド則を⼀一部満たしていない
⾮非モナド モナド機能を持っていないコンテナ
エラーハンドリング
コンテナ 種別 機能 パッケージ
Option モナド 失敗/成功の⽂文脈を保持 scala
Try 準モナド 例例外状態を保持 scala.util
Either ⾮非モナド 直和 scala.util
Validation モナド バリデーション scalaz
/ モナド 直和(右側を正としてモナド
化)
scalaz
Future 準モナド ⾮非同期(即時) scala.concurren
t
Promise モナド ⾮非同期(即時) scalaz.concurre
nt
Task モナド ⾮非同期(遅延) scalaz.concurre
nt
Scalaz
かんたん
便便利利機能: Boolean
scala> def bt: Boolean = true
bt: Boolean
scala> def bf: Boolean = false
bf: Boolean
scala> bt option 100
res8: Option[Int] = Some(100)
scala> bf option 100
res9: Option[Int] = None
scala> bt ?? 100
res11: Int = 100
scala> bf ?? 100
res10: Int = 0
scala> bt !? 100
res12: Int = 0
scala> bf !? 100
res13: Int = 100
かんたん
便便利利機能: Option
scala> val os = 100.some
os: Option[Int] = Some(100)
scala> val on = none[Int]
on: Option[Int] = None
scala> os ? "defined" | "undefined”
res14: String = defined
scala> on ? "defined" |
"undefined”
res15: String = undefined
scala> on.orZero
res16: Int = 0
scala> os | -1
res18: Int = 100
scala> on | -1
res17: Int = -1
scala> os.cata(_ + 1, -1)
res19: Int = 101
scala> on.cata(_ + 1, -1)
res20: Int = -1
かんたん
Monoid
•  代数的構造の概念念
•  http://ja.wikipedia.org/wiki/
%E3%83%A2%E3%83%8E%E3%82%A4%E3%83%89
•  A → A → A
•  2項演算⼦子
•  結合法則
•  単位元
•  演算
•  1 + 2 = 3
•  “abc” + “mno” = “abcmno”
•  List(“abc”) ++ List(“mno”) = List(“abcmno”)
結合法則
•  結合法則
•  (1 + 2) + 3 == 1 + (2 + 3)
•  (“abc” + “mno”) + “xyz” == “abc” + (“mno” + “xyz”)
•  単位元
•  1 + 0 == 0 + 1 == 1
•  “abc” + “” == “” + abc” == “abc
Monoidを使⽤用しないロジック
def sumi(xs: Vector[Int]): Int = sumi2(xs, 0)
def sumi2(xs: Vector[Int], acc: Int): Int = {
xs.headOption match {
case None => acc
case Some(x) => sum(xs.tail, acc + x)
}
}
Monoidを使⽤用したロジック
def summ[T: Monoid](xs: Vector[T]): T = {
val M = implicitly(Monoid[T])
summ2(xs, M.zero)
}
def summ2[T: Monoid](xs: Vector[T], acc: T): T = {
xs.headOption match {
case None => acc
case Some(x) => summ2(xs.tail, acc |+| x)
}
}
便便利利機能: Monoid
scala> val xs = Vector(1, 2, 3)
val xs = Vector(1, 2, 3)
xs: scala.collection.immutable.Vector[Int] = Vector(1, 2, 3)
scala> xs.concatenate
xs.concatenate
res3: Int = 6
scala> xs.foldLeft(0) { (z, x) => z + x }
xs.foldLeft(0) { (z, x) => z + x }
res4: Int = 6
scala> xs.foldLeft(0) { (z, x) => z |+| x }
xs.foldLeft(0) { (z, x) => z |+| x }
res5: Int = 6
かんたん
便便利利機能: Monoid
scala> xs.foldMap(x => x)
res87: Int = 6
scala> xs.foldMap(x => x + 1)
res88: Int = 9
かんたん
まとめ
•  Scalazの導⼊入を可能にする関数型プログラミングの基礎
知識識について簡単に紹介しました。
•  現時点では聞いておくだけでOK
•  まず導⼊入して欲しいScalaz機能を紹介しました。
•  便便利利機能
•  前提知識識不不要で便便利利に使えます。
•  Monoid
•  Scalazを使った最新の関数型プログラミングのパワーを前提知
識識不不要で実感できます。
END

More Related Content

実務者のためのかんたんScalaz