wakuwaku scala ~scala入門勉強会~ 資料
DESCRIPTION
2013/04/27 wakuwaku Scala ~Scala入門勉強会~ 資料 資料中のソースコードは Github にリポジトリがあります。 https://github.com/charlesvineyard/wakuwaku-scala1TRANSCRIPT
1
~ Scala 入門勉強会 ~
山中 瑞起2013/04/27
2
自己紹介
山中 瑞起(やまなかみずき)
■ Twitter:charlesvineyard■ facebook:山中 瑞起
■ 現在フリーランスのSE■ MilmSearchプロジェクトリーダー
メーリングリスト検索アプリを開発するOSP Scalaで開発(1年くらい) Playフレームワーク勉強中
僭越ながら本日の講師を 勤めさせていただきます!
よろしくお願いします!!
3
本日のアジェンダ
■Scala、関数型言語について■開発環境設定■HelloWorld■FizzBuzz を題材に Scala を学ぶ
値を返す if 値を返す for map と高階関数 map と無名関数 match-case(パターンマッチ) map と match-case 再帰とクロージャとコンス(分ける方) 末尾再帰とコンス(連結する方)
4
Scala ってどんな言語?
■オブジェクト指向言語と関数型言語の両方の特徴を持っている
最初は書きやすくなった Java 程度の感覚で大丈夫
関数型言語って難しいイメージだけど、Scala なら段階的に関数型言語っぽく書いていける
だから勉強しやすくてオトク
5
Scala ってどんな言語?
■JVM上で動く コンパイルすると Java の class ファイルができるということ
Javaの資産がそのまま使える
■静的型付け&型推論 コンパイル時の型チェックで安心安全 型推論
➔冗長な型の記述が省略可
6
関数型言語って?
■関数が値 Scalaでは関数(メソッド)が1つの型で表せられる
変数に関数を入れることができる
■副作用がないプログラム 副作用とは
➔ある変数の状態が変更され、処理に影響が出ること
副作用がないと➔コードの理解がしやすくバグが入りにくい➔並列処理がしやい➔マルチコア対応しやすい
7
Mutable Immutable
■Mutable(ミュータブル) 変更できる 変更するためにある 状態が変わるので関数型言語的には嫌われる
■Immutable(イミュータブル) 変更できない 関数型言語では好ましい
■変更できないのにプログラムは可能なのか?■今日はそこんとこ注目
8
環境設定
■ Eclipse インストール 公式サイトからダウンロード(種類はclassic)、解凍
Workspace は差し支えなければデフォルトで起動
■ Scalaプラグインインストール Scala IDE 公式サイト http://scala-ide.org/
Eclipse のバージョンに合ったインストール用URLをクリックしてコピーしておく
Eclipse の ヘルプ>新規ソフトウェアインストール から適宜インストール
9
HelloWorld
■HelloWorld.scala を作成 新規(new)→Scalaオブジェクト
➔名前「HelloWorld」➔ main メソッド定義にチェック➔赤字部分だけ記述
■実行は「実行」→「実行」 または 緑の三角ボタン
object HelloWorld { def main(args: Array[String]): Unit = { println("Hello World") }}
10
HelloWorld.scala 詳細
object HelloWorld { def main(args: Array[String]): Unit = { println("Hello World") }}
オブジェクト宣言● シングルトンオブジェクト● 他言語で言うところの static メソッドが
定義できるクラス
オブジェクト名
def 関数名(メソッド名)
関数定義
引数リスト
2つのときは(変数名: 型, 変数名: 型)の形: に続けて型を書く
戻り値の型
引数と同様 : に続けて型を書くUnit は戻り値がない時の型(void)。省略可戻り値ありのときは = を書く
標準出力関数
11
FizzBuzz問題文
■1~20までの数を1行ずつ表示する■ただし、3で割りきれる数の場合は数の代わりに「Fizz」と表示する
■5で割りきれる数の場合は数の代わりに「Buzz」と表示する
■3でも5でも割りきれる数の場合は「FizzBuzz」と表示する
12
FizzBuzz01~基本形~
object FizzBuzz01 { def main(args: Array[String]) { for (i <- 1 to 20) { if (i % 3 == 0 && i % 5 ==0) { println("FuzzBuzz") } else if (i % 3 == 0) { println("Fizz") } else if (i % 5 == 0) { println("Buzz") } else { println(i) } } }}
他の言語と同じように、 if を使って処理を書いてみましょう。
13
FizzBuzz01~基本形~
object FizzBuzz01 { def main(args: Array[String]) { for (i <- 1 to 20) { if (i % 3 == 0 && i % 5 ==0) { println("FuzzBuzz") } else if (i % 3 == 0) { println("Fizz") } else if (i % 5 == 0) { println("Buzz") } else { println(i) } } }}
14
FizzBuzz02 ~ifは値を返す~ の前説
// Good if val valMsg = if (date.getDate % 2 == 0) { "今日は偶数日です。" } else { "今日は奇数日です。" } println(valMsg)
// Bad if var varMsg: String = null if (date.getDate % 2 == 0) { varMsg = "今日は偶数日です。" } else { varMsg = "今日は奇数日です。" } println(varMsg)
15
FizzBuzz02 ~ifは値を返す~
object FizzBuzz01 { def main(args: Array[String]) { for (i <- 1 to 20) { if (i % 3 == 0 && i % 5 ==0) { println("FuzzBuzz") } else if (i % 3 == 0) { println("Fizz") } else if (i % 5 == 0) { println("Buzz") } else { println(i) } } }}
object FizzBuzz02 { def main(args: Array[String]) { for (i <- 1 to 20) { val line = if (i % 3 == 0 && i % 5 ==0) { "FuzzBuzz" } else if (i % 3 == 0) { "Fizz" } else if (i % 5 == 0) { "Buzz" } else { i } println(line) } }}
val、値を返す ifを使い、println が1つになるよう 処理を書いてみましょう。
16
FizzBuzz02 ~ifは値を返す~
object FizzBuzz01 { def main(args: Array[String]) { for (i <- 1 to 20) { if (i % 3 == 0 && i % 5 ==0) { println("FuzzBuzz") } else if (i % 3 == 0) { println("Fizz") } else if (i % 5 == 0) { println("Buzz") } else { println(i) } } }}
object FizzBuzz02 { def main(args: Array[String]) { for (i <- 1 to 20) { val line = if (i % 3 == 0 && i % 5 ==0) { "FuzzBuzz" } else if (i % 3 == 0) { "Fizz" } else if (i % 5 == 0) { "Buzz" } else { i } println(line) } }}
17
FizzBuzz03 ~for は yield で値を返す~ の前説
val lines = for (i <- 1 to 5) yield if (i == 1) "壱" else if (i == 2) "弐" else "参以上"
lines foreach println
// 実行結果壱弐参以上参以上参以上
18
FizzBuzz03 ~for は yield で値を返す~
object FizzBuzz03 { def main(args: Array[String]) { val lines = for (i <- 1 to 20) yield if (i % 3 == 0 && i % 5 ==0) { "FuzzBuzz" } else if (i % 3 == 0) { "Fizz" } else if (i % 5 == 0) { "Buzz" } else { i } lines foreach println }}
値を返す for , foreach を使い 処理を書いてみましょう。
19
FizzBuzz03 ~for は yield で値を返す~
object FizzBuzz03 { def main(args: Array[String]) { val lines = for (i <- 1 to 20) yield if (i % 3 == 0 && i % 5 ==0) { "FuzzBuzz" } else if (i % 3 == 0) { "Fizz" } else if (i % 5 == 0) { "Buzz" } else { i } lines foreach println }}
20
FizzBuzz04 ~ map と高階関数~ の前説
// map と高階関数を使った例
def twice(x: Int) = x * 2
(1 to 5) map { x => twice(x) } foreach println
// 省略形 (1 to 5) map { twice(_) } foreach println (1 to 5) map { twice } foreach println (1 to 5) map twice foreach println // やりすぎ?
// 実行結果246810
21
FizzBuzz04 ~ map と高階関数~
object FizzBuzz04 { def main(args: Array[String]) { def fizzbuzz(i: Int): String = if (i % 3 == 0 && i % 5 == 0) "FizzBuzz" else if (i % 3 == 0) "Fizz" else if (i % 5 == 0) "Buzz" else i.toString()
1 to 20 map { fizzbuzz } foreach println }}
引数が Int型1つで、String型を返す fizzbuzz という名前の関数を定義し、 map を使って処理を書いてみましょう。
22
FizzBuzz04 ~ map と高階関数~
object FizzBuzz04 { def main(args: Array[String]) { def fizzbuzz(i: Int): String = if (i % 3 == 0 && i % 5 == 0) "FizzBuzz" else if (i % 3 == 0) "Fizz" else if (i % 5 == 0) "Buzz" else i.toString()
1 to 20 map { fizzbuzz } foreach println }}
23
FizzBuzz04 ~ map と高階関数~ の後説
// foreach println も同じ形でした
(1 to 5) foreach { x => println(x) } (1 to 5) foreach { println(_) } (1 to 5) foreach println
24
FizzBuzz05 ~ map と無名関数~ の前説
(1 to 5) map { (x: Int) => x * 2 } foreach println
// 省略形(1 to 5) map { x => x * 2 } foreach println(1 to 5) map { _ * 2 } foreach println
// 実行結果246810
25
FizzBuzz05 ~ map と無名関数~
object FizzBuzz05 { def main(args: Array[String]) { (1 to 20) map { x => if (x % 3 == 0 && x % 5 == 0) "FizzBuzz" else if (x % 3 == 0) "Fizz" else if (x % 5 == 0) "Buzz" else x.toString } foreach println }}
map と無名関数を使って 処理を書いてみましょう。
26
FizzBuzz05 ~ map と無名関数~
object FizzBuzz05 { def main(args: Array[String]) { (1 to 20) map { x => if (x % 3 == 0 && x % 5 == 0) "FizzBuzz" else if (x % 3 == 0) "Fizz" else if (x % 5 == 0) "Buzz" else x.toString } foreach println }}
27
FizzBuzz06 ~ match-case ~ の前説 1/2
// 例1 val num = 1
val daiji = num match { case 1 => "壱" case 2 => "弐" case _ => "参以上" }
println(daiji)
// 実行結果壱
28
FizzBuzz06 ~ match-case ~ の前説 2/2
// 例2 val date = new Date
val msg = date.getDate match { case d if (d % 2 == 0) => "今日は偶数日です。" case _ => "今日は奇数日です。" }
println(msg)
// 実行結果(27日の場合)今日は奇数日です。
29
FizzBuzz06 ~ match-case ~
object FizzBuzz06 { def main(args: Array[String]) { (1 to 20) map { num => num match { case x if (x % 3 == 0 && x % 5 == 0) => "FizzBuzz" case x if (x % 3 == 0) => "Fizz" case x if (x % 5 == 0) => "Buzz" case x => x.toString() } } foreach println }}
match-case を使って 処理を書いてみましょう。
30
FizzBuzz06 ~ match-case ~
object FizzBuzz06 { def main(args: Array[String]) { (1 to 20) map { num => num match { case x if (x % 3 == 0 && x % 5 == 0) => "FizzBuzz" case x if (x % 3 == 0) => "Fizz" case x if (x % 5 == 0) => "Buzz" case x => x.toString() } } foreach println }}
31
FizzBuzz07 ~ map と match の省略 ~ の前説
val daijis = (1 to 5) map { num => num match { case 1 => "壱" case 2 => "弐" case _ => "参以上" } }
// 省略形 val daijis2 = (1 to 5) map { case 1 => "壱" case 2 => "弐" case _ => "参以上" }
32
FizzBuzz07 ~ map と match の省略 ~
object FizzBuzz07 { def main(args: Array[String]) { 1 to 20 map { case x if (x % 3 == 0 && x % 5 == 0) => "FizzBuzz" case x if (x % 3 == 0) => "Fizz" case x if (x % 5 == 0) => "Buzz" case x => x.toString() } foreach println }}
match を省略した 処理を書いてみましょう。
33
FizzBuzz07 ~ map と match の省略 ~
object FizzBuzz07 { def main(args: Array[String]) { 1 to 20 map { case x if (x % 3 == 0 && x % 5 == 0) => "FizzBuzz" case x if (x % 3 == 0) => "Fizz" case x if (x % 5 == 0) => "Buzz" case x => x.toString() } foreach println }}
34
FizzBuzz08 ~ 再帰、クロージャ、コンス(分ける) ~
import scala.collection.mutable.ListBuffer
object FizzBuzz08 { def main(args: Array[String]) { val lines = new ListBuffer[String]
def fizzbuzzRec(numbers: List[Int]) { numbers match { case Nil => case number :: tail => { lines.append(number match { case x if (x % 3 == 0 && x % 5 == 0) => "FizzBuzz" case x if (x % 3 == 0) => "Fizz" case x if (x % 5 == 0) => "Buzz" case x => x.toString }) fizzbuzzRec(tail) } } }
fizzbuzzRec(1 to 20 toList) lines foreach println }}
35
FizzBuzz09 ~ 末尾再帰、コンス(連結) ~
import scala.collection.mutable.ListBufferimport scala.annotation.tailrecobject FizzBuzz09 { def main(args: Array[String]) { def fizzbuzzRec(numbers: List[Int]): List[String] = { @tailrec def fizzbuzzRecLocal(accumulator: List[String], numbers: List[Int]): List[String] = { numbers match { case Nil => accumulator case number :: tail => fizzbuzzRecLocal( accumulator ::: List( number match { case x if (x % 3 == 0 && x % 5 == 0) => "FizzBuzz" case x if (x % 3 == 0) => "Fizz" case x if (x % 5 == 0) => "Buzz" case x => x.toString } ), tail ) } } fizzbuzzRecLocal(Nil, numbers) } fizzbuzzRec(1 to 20 toList) foreach println }}
36
おすすめ書籍
■ オブジェクト指向プログラマが次に読む本-Scalaで学ぶ関数脳入門 株式会社テクノロジックアート、長瀬 嘉秀、 町田 修一
■ Scalaスケーラブルプログラミング第2版Martin Odersky、Lex Spoon、Bill Venners、 羽生田 栄一
■ Scala実践プログラミング―オープンソース徹底活用小笠原 啓、尾崎 智仁、関 隆、 水島 宏太
■ Scalaプログラミング入門 デイビッド・ポラック、羽生田栄一、 大塚庸史