関数型プログラミング
2014-05-11 at ゆかむ勉強会
Suguru Hamazaki
Introduction to Scala Functional Programming
入�門
ご説明内容
Agenda
Scalaって?
関数型プログラミ
ングって?
ステートマシンをどう
やって実装するの?
もっと抽象化
できるよ!
便利な
ライブラリーがあるよ!
プログラミング言語
Scala Programming Language
オブジェクト指向と
関数型の融合
Have the best of both worlds.
Construct elegant class hierarchies
for maximum code reuse and
extensibilit...
But …
パラダイムシフトは難しい
A paradigm shift is difficult
関数型プログラミング
Functional Programming
純粋関数
Pure Function
純粋関数
Pure Function
• 関数の評価結果が引数の値のみに
よって決まり、同じ値を与えると
常に同じ値の結果を返す
• 関数の評価によって、観測可能な
副作用が発生しない
f
x y
副作用の例Side effects examples
• 変数に再代入する
• データの構造を破壊的に変更する
• オブジェクトのフィールドに値をセットする
• 例外を投げる、エラー時に終了する
• コンソールに出力する、ユーザー入力を読む
• ファイルを読み書きする
• スクリーンに描画する
V...
純粋関数プログラムを書く
Write programs using only
pure functions
のみで
えっ?
コインのモデル
A coin model
head tail
flip
flip
stay stay
オブジェクト指向的コイン
case class OoCoin(private var head: Boolean) {	
def flip() = { head = !head }	
def stay() = {} // do nothing	...
オブジェクト指向的コイン
case class OoCoin(private var head: Boolean) {	
def flip() = { head = !head }	
def stay() = {} // do nothing	...
val c = OoCoin(true)	
c.flip()	
c.stay()	
c.flip()	
println("Showing a head? " + c.get)
参照透過性
Referential Transparency
ある式の中で、その式の
値を変えることなく、
等しいもの同士を 置換できること
val a = 5	
sumOfSquares(a + 1, a * 2)
def square(i: Int) = i * i 	
def sumOfSquares(i1: Int, i2: Int) =	
square(i1) + squa...
val a = 5	
sumOfSquares(a + 1, a * 2)
def square(i: Int) = i * i 	
def sumOfSquares(i1: Int, i2: Int) =	
square(i1) + squa...
val a = 5	
sumOfSquares(a + 1, a * 2)
def square(i: Int) = i * i 	
def sumOfSquares(i1: Int, i2: Int) =	
square(i1) + squa...
置換モデル
sumOfSquares(a + 1, a * 2)	
sumOfSquares(5 + 1, 5 * 2)	
sumOfSquares(6, 10)	
square(6) + square(10)	
(6 * 6) + (10 *...
再び、コインの例を見てみる
OK, let’s go back to the coin model
val c = OoCoin(true)	
c.flip()	
c.stay()	
c.flip()	
println("Showing a head? " + c.get)
val c = OoCoin(true)	
c.flip()	
c.stay()	
c.flip()	
println("Showing a head? " + c.get)
mutable なデータ構造と
非純粋関数
val c = OoCoin(true)	
c.flip()	
c.stay()	
c.flip()	
println("Showing a head? " + c.get)
mutable なデータ構造と
非純粋関数
参照透過性は?
不変なコインと
純粋関数を使う
Use immutable coins
and pure functions
case class Coin(head: Boolean)	
!
object Coin1 {	
def flip(c: Coin) = Coin(!c.head)	
def stay(c: Coin) = c	
}
case class Coin(head: Boolean)	
!
object Coin1 {	
def flip(c: Coin) = Coin(!c.head)	
def stay(c: Coin) = c	
}	
case class ...
case class Coin(head: Boolean)	
!
object Coin1 {	
def flip(c: Coin) = Coin(!c.head)	
def stay(c: Coin) = c	
}	
case class ...
val c0 = Coin(true)	
val c1 = flip(c0)	
val c2 = stay(c1)	
val c3 = flip(c2)	
println("Showing a head? " + c3.head)
val c0 = Coin(true)	
val c1 = flip(c0)	
val c2 = stay(c1)	
val c3 = flip(c2)	
println("Showing a head? " + c3.head)
コインの 操作
クラスで表現してみる
を
Express an ‘Action’ of a coin with a class
case class CoinAction(action: Coin => Coin) extends (Coin => Coin) {	
def apply(c: Coin) = action(c)	
def +(next: CoinActi...
case class CoinAction(action: Coin => Coin) extends (Coin => Coin) {	
def apply(c: Coin) = action(c)	
def +(next: CoinActi...
case class CoinAction(action: Coin => Coin) extends (Coin => Coin) {	
def apply(c: Coin) = action(c)	
def +(next: CoinActi...
case class CoinAction(action: Coin => Coin) extends (Coin => Coin) {	
def apply(c: Coin) = action(c)	
def +(next: CoinActi...
case class CoinAction(action: Coin => Coin) extends (Coin => Coin) {	
def apply(c: Coin) = action(c)	
def +(next: CoinActi...
First class Functions
• 引数として渡せる
• 戻り値として返せる
• 変数に代入できる
val flip = CoinAction(c => Coin(!c.head))	
val stay = CoinAction(c => c)
flip, stay を CoinAction の
インスタンスとして定義
val action = flip + stay + flip	
val c = action(Coin(true))	
println("Showing a head? " + c.head)
+() メソッドで操作を
1つにまとめる
val action = flip + stay + flip	
val c = action(Coin(true))	
println("Showing a head? " + c.head)
+() メソッドで操作を
1つにまとめる
でも、...
case class CoinAction[A](action: Coin => (Coin, A))	
extends (Coin => (Coin, A)) {	
def apply(c: Coin) = action(c)	
def +[...
case class CoinAction[A](action: Coin => (Coin, A))	
extends (Coin => (Coin, A)) {	
def apply(c: Coin) = action(c)	
def +[...
case class CoinAction[A](action: Coin => (Coin, A))	
extends (Coin => (Coin, A)) {	
def apply(c: Coin) = action(c)	
def +[...
case class CoinAction[A](action: Coin => (Coin, A))	
extends (Coin => (Coin, A)) {	
def apply(c: Coin) = action(c)	
def +[...
val flip = CoinAction { c =>	
val head = !c.head	
(Coin(head), head)	
}	
val stay = CoinAction(c => (c, c.head))
val flip = CoinAction { c =>	
val head = !c.head	
(Coin(head), head)	
}	
val stay = CoinAction(c => (c, c.head))
Coinと一緒に
...
val action =	
flip.flatMap { _ =>	
stay.flatMap { _ =>	
flip	
}	
}	
val (c, _) = action(Coin(true))	
println("Showing a he...
val action =	
flip.flatMap { _ =>	
stay.flatMap { _ =>	
flip	
}	
}	
val (c, _) = action(Coin(true))	
println("Showing a he...
val action =	
flip.flatMap { _ =>	
stay.flatMap { _ =>	
flip	
}	
}	
val (c, _) = action(Coin(true))	
println("Showing a he...
val action =	
flip.flatMap { b1 =>	
stay.flatMap { _ =>	
flip.map { b3 =>	
(b1, b3)	
}	
}	
}	
val (_, (b1, b3)) = action(C...
val action =	
flip.flatMap { b1 =>	
stay.flatMap { _ =>	
flip.map { b3 =>	
(b1, b3)	
}	
}	
}	
val (_, (b1, b3)) = action(C...
val action =	
flip.flatMap { b1 =>	
stay.flatMap { _ =>	
flip.map { b3 =>	
(b1, b3)	
}	
}	
}	
val (_, (b1, b3)) = action(C...
val action =	
flip.flatMap { b1 =>	
stay.flatMap { _ =>	
flip.map { b3 =>	
(b1, b3)	
}	
}	
}	
val (_, (b1, b3)) = action(C...
val action = for {	
b1 <- flip	
_ <- stay	
b3 <- flip	
} yield (b1, b3)	
val (_, (b1, b3)) = action(Coin(true))	
println("...
val action = for {	
s1 <- flip.map(b1 => "1st occurrence is a head? " + b1)	
_ <- stay	
s3 <- flip.map(b3 => "3rd occurren...
val action = for {	
s1 <- flip.map(b1 => "1st occurrence is a head? " + b1)	
_ <- stay	
s3 <- flip.map(b3 => "3rd occurren...
CoinActionを抽象化
case class CoinAction[A](action: Coin => (Coin, A))	
extends (Coin => (Coin, A)) {	
def apply(c: Coin) = action(c)	
def +[...
case class CoinAction[A](action: Coin => (Coin, A))	
extends (Coin => (Coin, A)) {	
def apply(c: Coin) = action(c)	
def +[...
case class State[S, +A](run: S => (S, A)) {	
def map[B](f: A => B): State[S, B] =	
State { s =>	
val (s2, a) = run(s)	
(s2...
type CoinAction[A] = State[Coin, A]	
val flip: CoinAction[Boolean] = State { c =>	
val head = !c.head	
(Coin(head), head)	...
先ほどと同じように
使えます
Wait …
それ
でできるよ
Scalaz
Scalaz
Scalaz provides purely functional
data structures to complement those
from the Scala standard library.
— from http:...
import scalaz.State	
type CoinAction[A] = State[Coin, A]
scalaz の State を使う
先ほどと同じように
使えます
まとめ
Summary
ScalaはOOとFPがミックスした
マルチパラダイム言語
関数型プログラミングでは
純粋関数を使う
状態遷移を表わす
CoinAction を作り、ステート
マシンを実装した
CoinAction を
State とし...
詳しい解説ドキュメント&
完全なソースコードはこちら
https://github.com/hamazy/scala-fp-calisthenics
Q&A
Image Credits
Introduction to Scala Functional Programming
Upcoming SlideShare
Loading in...5
×

Introduction to Scala Functional Programming

503

Published on

2 Comments
1 Like
Statistics
Notes
No Downloads
Views
Total Views
503
On Slideshare
0
From Embeds
0
Number of Embeds
1
Actions
Shares
0
Downloads
7
Comments
2
Likes
1
Embeds 0
No embeds

No notes for slide

Introduction to Scala Functional Programming

  1. 1. 関数型プログラミング 2014-05-11 at ゆかむ勉強会 Suguru Hamazaki Introduction to Scala Functional Programming 入�門
  2. 2. ご説明内容 Agenda Scalaって? 関数型プログラミ ングって? ステートマシンをどう やって実装するの? もっと抽象化 できるよ! 便利な ライブラリーがあるよ!
  3. 3. プログラミング言語 Scala Programming Language
  4. 4. オブジェクト指向と 関数型の融合 Have the best of both worlds. Construct elegant class hierarchies for maximum code reuse and extensibility, implement their behavior using higher-order functions. Or anything in-between. — from http://www.scala-lang.org/ Object-Oriented Meets Functional
  5. 5. But …
  6. 6. パラダイムシフトは難しい A paradigm shift is difficult
  7. 7. 関数型プログラミング Functional Programming
  8. 8. 純粋関数 Pure Function
  9. 9. 純粋関数 Pure Function • 関数の評価結果が引数の値のみに よって決まり、同じ値を与えると 常に同じ値の結果を返す • 関数の評価によって、観測可能な 副作用が発生しない f x y
  10. 10. 副作用の例Side effects examples
  11. 11. • 変数に再代入する • データの構造を破壊的に変更する • オブジェクトのフィールドに値をセットする • 例外を投げる、エラー時に終了する • コンソールに出力する、ユーザー入力を読む • ファイルを読み書きする • スクリーンに描画する Variable reassigning Destructive mutation Setting field values Throwing exceptions or stopping at failure Console output or reading user input File I/O Displaying to screen
  12. 12. 純粋関数プログラムを書く Write programs using only pure functions のみで
  13. 13. えっ?
  14. 14. コインのモデル A coin model
  15. 15. head tail flip flip stay stay
  16. 16. オブジェクト指向的コイン case class OoCoin(private var head: Boolean) { def flip() = { head = !head } def stay() = {} // do nothing def get = head } Object-Oriented Coin
  17. 17. オブジェクト指向的コイン case class OoCoin(private var head: Boolean) { def flip() = { head = !head } def stay() = {} // do nothing def get = head } var (variable) で宣言し たフィールドに再代入 Object-Oriented Coin
  18. 18. val c = OoCoin(true) c.flip() c.stay() c.flip() println("Showing a head? " + c.get)
  19. 19. 参照透過性 Referential Transparency
  20. 20. ある式の中で、その式の 値を変えることなく、 等しいもの同士を 置換できること
  21. 21. val a = 5 sumOfSquares(a + 1, a * 2) def square(i: Int) = i * i def sumOfSquares(i1: Int, i2: Int) = square(i1) + square(i2)
  22. 22. val a = 5 sumOfSquares(a + 1, a * 2) def square(i: Int) = i * i def sumOfSquares(i1: Int, i2: Int) = square(i1) + square(i2) 純粋な関数
  23. 23. val a = 5 sumOfSquares(a + 1, a * 2) def square(i: Int) = i * i def sumOfSquares(i1: Int, i2: Int) = square(i1) + square(i2) 純粋な関数 再代入できない val
  24. 24. 置換モデル sumOfSquares(a + 1, a * 2) sumOfSquares(5 + 1, 5 * 2) sumOfSquares(6, 10) square(6) + square(10) (6 * 6) + (10 * 10) 36 + 100 136 Substitution Model http://mitpress.mit.edu/sicp/full-text/book/book-Z-H-10.html
  25. 25. 再び、コインの例を見てみる OK, let’s go back to the coin model
  26. 26. val c = OoCoin(true) c.flip() c.stay() c.flip() println("Showing a head? " + c.get)
  27. 27. val c = OoCoin(true) c.flip() c.stay() c.flip() println("Showing a head? " + c.get) mutable なデータ構造と 非純粋関数
  28. 28. val c = OoCoin(true) c.flip() c.stay() c.flip() println("Showing a head? " + c.get) mutable なデータ構造と 非純粋関数 参照透過性は?
  29. 29. 不変なコインと 純粋関数を使う Use immutable coins and pure functions
  30. 30. case class Coin(head: Boolean) ! object Coin1 { def flip(c: Coin) = Coin(!c.head) def stay(c: Coin) = c }
  31. 31. case class Coin(head: Boolean) ! object Coin1 { def flip(c: Coin) = Coin(!c.head) def stay(c: Coin) = c } case class のフィー ルドはデフォルトで immutable
  32. 32. case class Coin(head: Boolean) ! object Coin1 { def flip(c: Coin) = Coin(!c.head) def stay(c: Coin) = c } case class のフィー ルドはデフォルトで immutable 受け取ったCoinは変更せず、新しいCoinを生成
  33. 33. val c0 = Coin(true) val c1 = flip(c0) val c2 = stay(c1) val c3 = flip(c2) println("Showing a head? " + c3.head)
  34. 34. val c0 = Coin(true) val c1 = flip(c0) val c2 = stay(c1) val c3 = flip(c2) println("Showing a head? " + c3.head)
  35. 35. コインの 操作 クラスで表現してみる を Express an ‘Action’ of a coin with a class
  36. 36. case class CoinAction(action: Coin => Coin) extends (Coin => Coin) { def apply(c: Coin) = action(c) def +(next: CoinAction): CoinAction = CoinAction { c0 => val c1 = action(c0) next(c1) } }
  37. 37. case class CoinAction(action: Coin => Coin) extends (Coin => Coin) { def apply(c: Coin) = action(c) def +(next: CoinAction): CoinAction = CoinAction { c0 => val c1 = action(c0) next(c1) } } Coinの状態を遷移さ せる関数をラップ
  38. 38. case class CoinAction(action: Coin => Coin) extends (Coin => Coin) { def apply(c: Coin) = action(c) def +(next: CoinAction): CoinAction = CoinAction { c0 => val c1 = action(c0) next(c1) } } Coinの状態を遷移さ せる関数をラップ 自身も関数として扱える
  39. 39. case class CoinAction(action: Coin => Coin) extends (Coin => Coin) { def apply(c: Coin) = action(c) def +(next: CoinAction): CoinAction = CoinAction { c0 => val c1 = action(c0) next(c1) } } Coinの状態を遷移さ せる関数をラップ 自身も関数として扱える 「コインを受け取った時に、自 身の action を実行してから、次 の操作を実行する」という関数
  40. 40. case class CoinAction(action: Coin => Coin) extends (Coin => Coin) { def apply(c: Coin) = action(c) def +(next: CoinAction): CoinAction = CoinAction { c0 => val c1 = action(c0) next(c1) } } Coinの状態を遷移さ せる関数をラップ 自身も関数として扱える 関数として呼び出された際に、 ラップした関数を実行 「コインを受け取った時に、自 身の action を実行してから、次 の操作を実行する」という関数
  41. 41. First class Functions • 引数として渡せる • 戻り値として返せる • 変数に代入できる
  42. 42. val flip = CoinAction(c => Coin(!c.head)) val stay = CoinAction(c => c) flip, stay を CoinAction の インスタンスとして定義
  43. 43. val action = flip + stay + flip val c = action(Coin(true)) println("Showing a head? " + c.head) +() メソッドで操作を 1つにまとめる
  44. 44. val action = flip + stay + flip val c = action(Coin(true)) println("Showing a head? " + c.head) +() メソッドで操作を 1つにまとめる でも、途中の結果も 欲しい時は?
  45. 45. case class CoinAction[A](action: Coin => (Coin, A)) extends (Coin => (Coin, A)) { def apply(c: Coin) = action(c) def +[B](next: CoinAction[B]): CoinAction[B] = flatMap(_ => next) def map[B](f: A => B): CoinAction[B] = CoinAction { c0 => val (c1, a) = apply(c0) (c1, f(a)) } def flatMap[B](f: A => CoinAction[B]): CoinAction[B] = CoinAction { c0 => val (c1, a) = apply(c0) f(a)(c1) } }
  46. 46. case class CoinAction[A](action: Coin => (Coin, A)) extends (Coin => (Coin, A)) { def apply(c: Coin) = action(c) def +[B](next: CoinAction[B]): CoinAction[B] = flatMap(_ => next) def map[B](f: A => B): CoinAction[B] = CoinAction { c0 => val (c1, a) = apply(c0) (c1, f(a)) } def flatMap[B](f: A => CoinAction[B]): CoinAction[B] = CoinAction { c0 => val (c1, a) = apply(c0) f(a)(c1) } } Coinと一緒に任意の型の結果を返す
  47. 47. case class CoinAction[A](action: Coin => (Coin, A)) extends (Coin => (Coin, A)) { def apply(c: Coin) = action(c) def +[B](next: CoinAction[B]): CoinAction[B] = flatMap(_ => next) def map[B](f: A => B): CoinAction[B] = CoinAction { c0 => val (c1, a) = apply(c0) (c1, f(a)) } def flatMap[B](f: A => CoinAction[B]): CoinAction[B] = CoinAction { c0 => val (c1, a) = apply(c0) f(a)(c1) } } Coinと一緒に任意の型の結果を返す 遷移した結果を 任意の型に変換する
  48. 48. case class CoinAction[A](action: Coin => (Coin, A)) extends (Coin => (Coin, A)) { def apply(c: Coin) = action(c) def +[B](next: CoinAction[B]): CoinAction[B] = flatMap(_ => next) def map[B](f: A => B): CoinAction[B] = CoinAction { c0 => val (c1, a) = apply(c0) (c1, f(a)) } def flatMap[B](f: A => CoinAction[B]): CoinAction[B] = CoinAction { c0 => val (c1, a) = apply(c0) f(a)(c1) } } Coinと一緒に任意の型の結果を返す 遷移した結果を 任意の型に変換する 次の操作と組み合わせる。ただし、 前の結果を元に次の操作を生成する 関数として受け取る
  49. 49. val flip = CoinAction { c => val head = !c.head (Coin(head), head) } val stay = CoinAction(c => (c, c.head))
  50. 50. val flip = CoinAction { c => val head = !c.head (Coin(head), head) } val stay = CoinAction(c => (c, c.head)) Coinと一緒に Boolean 型の結果を 返す
  51. 51. val action = flip.flatMap { _ => stay.flatMap { _ => flip } } val (c, _) = action(Coin(true)) println("Showing a head? " + c.head)
  52. 52. val action = flip.flatMap { _ => stay.flatMap { _ => flip } } val (c, _) = action(Coin(true)) println("Showing a head? " + c.head) flip + stay + flip と 同様のコード
  53. 53. val action = flip.flatMap { _ => stay.flatMap { _ => flip } } val (c, _) = action(Coin(true)) println("Showing a head? " + c.head) flip + stay + flip と 同様のコード ただし、単なる CoinActionではなく、CoinAction を返 す関数を渡している
  54. 54. val action = flip.flatMap { b1 => stay.flatMap { _ => flip.map { b3 => (b1, b3) } } } val (_, (b1, b3)) = action(Coin(true)) println("1st occurrence is a head? " + b1) println("3rd occurrence is a head? " + b3)
  55. 55. val action = flip.flatMap { b1 => stay.flatMap { _ => flip.map { b3 => (b1, b3) } } } val (_, (b1, b3)) = action(Coin(true)) println("1st occurrence is a head? " + b1) println("3rd occurrence is a head? " + b3) 結果が Tuple になるよう map() で変換
  56. 56. val action = flip.flatMap { b1 => stay.flatMap { _ => flip.map { b3 => (b1, b3) } } } val (_, (b1, b3)) = action(Coin(true)) println("1st occurrence is a head? " + b1) println("3rd occurrence is a head? " + b3) 結果が Tuple になるよう map() で変換 flatMap() が受けるのは、今の操作の結果から、次回以降の操作を作る関数。
  57. 57. val action = flip.flatMap { b1 => stay.flatMap { _ => flip.map { b3 => (b1, b3) } } } val (_, (b1, b3)) = action(Coin(true)) println("1st occurrence is a head? " + b1) println("3rd occurrence is a head? " + b3) 結果が Tuple になるよう map() で変換 flatMap() が受けるのは、今の操作の結果から、次回以降の操作を作る関数。 なので、b1, b3 がネスト した内部ブロックで利用 できる
  58. 58. val action = for { b1 <- flip _ <- stay b3 <- flip } yield (b1, b3) val (_, (b1, b3)) = action(Coin(true)) println("1st occurrence is a head? " + b1) println("3rd occurrence is a head? " + b3) map(), flatMap() があれば、for-comprehension が使える
  59. 59. val action = for { s1 <- flip.map(b1 => "1st occurrence is a head? " + b1) _ <- stay s3 <- flip.map(b3 => "3rd occurrence is a head? " + b3) } yield (s1 + "n" + s3) val (_, s) = action(Coin(true)) println(s)
  60. 60. val action = for { s1 <- flip.map(b1 => "1st occurrence is a head? " + b1) _ <- stay s3 <- flip.map(b3 => "3rd occurrence is a head? " + b3) } yield (s1 + "n" + s3) val (_, s) = action(Coin(true)) println(s) この時点で、 CoinAction[Boolean] を CoinAction[String] に変換して しまう
  61. 61. CoinActionを抽象化
  62. 62. case class CoinAction[A](action: Coin => (Coin, A)) extends (Coin => (Coin, A)) { def apply(c: Coin) = action(c) def +[B](next: CoinAction[B]): CoinAction[B] = flatMap(_ => next) def map[B](f: A => B): CoinAction[B] = CoinAction { c0 => val (c1, a) = apply(c0) (c1, f(a)) } def flatMap[B](f: A => CoinAction[B]): CoinAction[B] = CoinAction { c0 => val (c1, a) = apply(c0) f(a)(c1) } }
  63. 63. case class CoinAction[A](action: Coin => (Coin, A)) extends (Coin => (Coin, A)) { def apply(c: Coin) = action(c) def +[B](next: CoinAction[B]): CoinAction[B] = flatMap(_ => next) def map[B](f: A => B): CoinAction[B] = CoinAction { c0 => val (c1, a) = apply(c0) (c1, f(a)) } def flatMap[B](f: A => CoinAction[B]): CoinAction[B] = CoinAction { c0 => val (c1, a) = apply(c0) f(a)(c1) } } Coin のメソッドをどこ からも呼び出してない
  64. 64. case class State[S, +A](run: S => (S, A)) { def map[B](f: A => B): State[S, B] = State { s => val (s2, a) = run(s) (s2, f(a)) } def flatMap[B](f: A => State[S, B]): State[S, B] = State { s => val (s2, a) = run(s) f(a).run(s2) } } Coin を型パラメーター S として抽象化 Functional Programming in Scala http://www.manning.com/bjarnason/ より抜粋、一部改変
  65. 65. type CoinAction[A] = State[Coin, A] val flip: CoinAction[Boolean] = State { c => val head = !c.head (Coin(head), head) } val stay: CoinAction[Boolean] = State(c => (c, c.head)) CoinAction を type alias として定義
  66. 66. 先ほどと同じように 使えます
  67. 67. Wait …
  68. 68. それ でできるよ Scalaz
  69. 69. Scalaz Scalaz provides purely functional data structures to complement those from the Scala standard library. — from http://typelevel.org/projects/scalaz/
  70. 70. import scalaz.State type CoinAction[A] = State[Coin, A] scalaz の State を使う
  71. 71. 先ほどと同じように 使えます
  72. 72. まとめ Summary ScalaはOOとFPがミックスした マルチパラダイム言語 関数型プログラミングでは 純粋関数を使う 状態遷移を表わす CoinAction を作り、ステート マシンを実装した CoinAction を State として抽象化 Scalaz の State を紹介
  73. 73. 詳しい解説ドキュメント& 完全なソースコードはこちら https://github.com/hamazy/scala-fp-calisthenics
  74. 74. Q&A
  75. 75. Image Credits
  1. A particular slide catching your eye?

    Clipping is a handy way to collect important slides you want to go back to later.

×