hokuriku scala 1

21
作用 作用 西本圭佑 (NISHIMOTO Keisuke) [email protected] Hokuriku. Hokuriku. 第一回 第一回

Upload: nishimoto-keisuke

Post on 09-Jul-2015

1.387 views

Category:

Technology


0 download

TRANSCRIPT

Page 1: Hokuriku Scala 1

副副作用作用

西本圭佑 (NISHIMOTO Keisuke)[email protected]

Hokuriku. Hokuriku. 第一回第一回

Page 2: Hokuriku Scala 1

2009/09/26 Hokuriku.Scala 第一回 2

自己紹介

➔ 緒言➔ 西本 圭佑➔ NISHIMOTO Keisuke➔ [email protected]➔ Twitter: keisuke_n

➔ 仕事➔ Webアプリケーションの開発・支援

➔ それにかかわる導入・運用

Page 3: Hokuriku Scala 1

2009/09/26 Hokuriku.Scala 第一回 3

自己紹介

➔ 趣味➔ プログラミング(なんでも)➔ 電子工作➔ 鉄道全般: 乗ること, 調べること

➔ 今日は、新幹線にサンダーバードを堪能

➔ 使用言語➔ Java, Ruby, JavaScript, ActionScript, C#, PHP➔ そして Scala

Page 4: Hokuriku Scala 1

2009/09/26 Hokuriku.Scala 第一回 4

自己紹介

➔ 今月は勉強会デー、順次北上中...

➔ 9/12 岡山: オープンラボ岡山➔ ScalaでAndroidアプリケーションの開発

➔ 9/19 京都: Ruby/Rails勉強会@関西➔ 自作ハードウェアをRubyから操作

➔ 9/26 富山: Hokuriku.Scala➔ 副作用について語る

Page 5: Hokuriku Scala 1

2009/09/26 Hokuriku.Scala 第一回 5

副作用とは

➔ プログラミングにおける副作用とは、ある機能がコンピュータの(論理的な)状態を変化させ、それ以降で得られる結果に影響を与えること➔ Wikipedia - 副作用 (プログラム)より

➔ 副作用によって参照透過性が失われる

Page 6: Hokuriku Scala 1

2009/09/26 Hokuriku.Scala 第一回 6

副作用とは

➔ 参照透過性 (Referential transparency)➔ 文脈によらず式の値はその構成要素(変数や関数など)

によってのみ定まるということ➔ 変数の値は最初に定義した値と常に同じであり、関数

の引数が同じ値であれば同じ値を返す➔ 変数に値を割り当てなおす代入がない➔ 参照透過性が成り立っている場合、ある式の値、例え

ば関数値、変数値についてどこに記憶されているか参照しているかを考慮する必要がない、即ち参照について透過的である

➔ Wikipedia - 参照透過性より

Page 7: Hokuriku Scala 1

2009/09/26 Hokuriku.Scala 第一回 7

副作用とは

➔ 副作用を伴う例➔ I/O制御(write/print等)、➔ 破壊的代入

➔ ノイマン型のアーキテクチャは副作用を前提として動作するため、多くのプログラミング言語では変数の破壊的代入機能を持つ。

➔ 副作用を伴わない例➔ 破壊的代入を行わない

➔ 定数➔ 変数をその処理の範囲では定数として扱う(再代入されない)

➔ モナドによる副作用の抽象化

Page 8: Hokuriku Scala 1

2009/09/26 Hokuriku.Scala 第一回 8

副作用を排除すると

➔ 長所➔ いかなる状況でも常に同じ結果が得られるために、機

能を純粋にアルゴリズムとして定義でき、状況依存でのバグの発生が抑えられる

➔ 短所➔ ノイマン型アーキテクチャと反りが合わず、効率の点で

不利になることが多い➔ 単純な逐次処理を行う場合は状態を中心に命令的な

思考をした方が扱いやすい場合がある

Page 9: Hokuriku Scala 1

2009/09/26 Hokuriku.Scala 第一回 9

例: フィボナッチ数列

➔ フィボナッチ数列の式➔ F0 = 0, F1 = 1➔ Fn+2 = Fn + Fn+1 (n >= 0)

➔ 0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987, …

➔ プログラムで使いやすい形に変換➔ F0 = 0, F1 = 1➔ Fn = Fn-2 + Fn-1 (n >= 2)

Page 10: Hokuriku Scala 1

2009/09/26 Hokuriku.Scala 第一回 10

例: フィボナッチ数列

➔ 副作用のないコード(Scala)def fib(n: Int): Int = if (n < 2) n else fib(n-2) + fib(n-1)

➔ 再帰呼び出し➔ 式による表現➔ 状態変数なし(参照透過性)

Page 11: Hokuriku Scala 1

2009/09/26 Hokuriku.Scala 第一回 11

例: フィボナッチ数列

➔ 副作用のあるコード(Scala)def fib(n: Int): Int = { if (n < 2) n else { var fnm2 = 0; var fnm1 = 1; var fn = 0 for (i <- 2 to n) { fn = fnm2 + fnm1 fnm2 = fnm1; fnm1 = fn } fn }}

Page 12: Hokuriku Scala 1

2009/09/26 Hokuriku.Scala 第一回 12

例: フィボナッチ数列

➔ 副作用のあるコード(Java)public int fib(int n) { if (n < 2) return n; else { int fnm2 = 0; int fnm1 = 1; int fn = 0; for (int i = 2; i <= n; i++) { fn = fnm2 + fnm1; fnm2 = fnm1; fnm1 = fn; } return fn; }}

Page 13: Hokuriku Scala 1

2009/09/26 Hokuriku.Scala 第一回 13

例: フィボナッチ数列

➔ 副作用のあるコード

➔ ループ変数(破壊的代入)➔ 参照透過性がない(状態が書き換わる)

➔ 状態の書き換えの順番は重要(因果律)➔ 状態を表す変数がたくさん作られる➔ (この例では)見通しが悪い

Page 14: Hokuriku Scala 1

2009/09/26 Hokuriku.Scala 第一回 14

Scalaで副作用を取り除くには

➔ 文法➔ 再代入できない変数: val

val str1 = "Hello"val str2 = "world"val result = str1 + ", " + str2 + "!"// "Hello, world!"

Page 15: Hokuriku Scala 1

2009/09/26 Hokuriku.Scala 第一回 15

Scalaで副作用を取り除くには

➔ 文法➔ すべてが式: if, match, try catch, ...

val str = "1234"val result = try { str.toInt } catch { case NumberFormatException => -1 }// result = 1234

Page 16: Hokuriku Scala 1

2009/09/26 Hokuriku.Scala 第一回 16

Scalaで副作用を取り除くには

➔ 文法➔ 再帰呼び出し

➔ 再帰呼び出しの最適化(末尾再帰)

val start = 1val end = 10def sum(i: Int, v: Int): Int = if (i <= end) sum(i + 1, v + i) else vval result = sum(start, 0) // 55

Page 17: Hokuriku Scala 1

2009/09/26 Hokuriku.Scala 第一回 17

Scalaで副作用を取り除くには

➔ API➔ 繰り返しユーティリティメソッド: map, filter, ...

List(1, 2, 3).map {i => i * 2}// List(2, 4, 6)Array(1, 2, 3, 4).filter {_ % 2 == 0}// Array(2, 4)List(1, 2, 3, 4, 5).takeWhile {_ <= 3}// List(1, 2, 3)(1 to 10).foldLeft(0) {(sum, a) => sum + a}// 55

Page 18: Hokuriku Scala 1

Scalaで副作用を取り除くには

➔ API➔ Immutableなコレクション:

scala.collection.immutable._

import scala.collection.immutable.HashMapval map1 = HashMap('a -> 1, 'b -> 2)val map2 = map1 + ('c -> 3)// map1: HashMap('a->1, 'b->2)// map2: HashMap('a->1, 'b->2, 'c->3)

Page 19: Hokuriku Scala 1

2009/09/26 Hokuriku.Scala 第一回 19

まとめ

➔ 副作用をなくすといいことがある➔ (状態がないので)シンプルになるかもしれない

➔ (状態がないので)バグが抑えられるかもしれない

➔ 副作用をなくすことによる問題➔ 場合によっては複雑になるかもしれない➔ 特に逐次処理

➔ Scalaには副作用を抑えるサポートがある

Page 20: Hokuriku Scala 1

2009/09/26 Hokuriku.Scala 第一回 20

おわり

ご清聴ありがとうございました

Page 21: Hokuriku Scala 1

2009/09/26 Hokuriku.Scala 第一回 21

質疑応答

Any Questions?