23
15分でざっくり分かるScala入門 佐藤 祐一郎 JAIST IS 2014/6/21 kanazawa.rb meetup#22 1

15分でざっくり分かるScala入門

Embed Size (px)

DESCRIPTION

佐藤 祐一郎 JAIST IS 2014/6/21 kanazawa.rb meetup#22

Citation preview

Page 1: 15分でざっくり分かるScala入門

15分でざっくり分かるScala入門

佐藤 祐一郎 JAIST IS 2014/6/21 kanazawa.rb meetup#22

1

Page 2: 15分でざっくり分かるScala入門

自己紹介

2

佐藤 祐一郎

北陸先端科学技術大学院大学

情報科学研究科 博士後期2年

人工知能作ってます

Page 3: 15分でざっくり分かるScala入門

Scalaのいいところ

3

JVM上で動く

(Javaのライブラリ

Java用のフレームワークなどに組み込める)

オブジェクト指向+関数型

きれいなJava

個人的には困った時はJavaっぽく書けるし、Lispっぽくも書けるし好き

Page 4: 15分でざっくり分かるScala入門

Scala早見表 リテラル

4

Scala Java

Int int

Long long

Double double

Boolean boolean

String String

Tuple

Elem(xml)

その他Javaにあるものはある

val x : Int = 1 var str : String = “hoge” val tuple = (1, “hoge”) val xml = <xml><body>text</body></xml>

val 再代入不可 できるだけこっちを使う var 再代入できる できるだけ使わない

Page 5: 15分でざっくり分かるScala入門

Scala早見表 制御構文

5

Scala Java

if (i < 10) { … } else { … } if (i < 10) { … } else { … }

while(i < 10){ … } while(i < 10) { … }

for(o : Object <- list) { … } for(Object o : list) { … }

n match { case 1 => … case 2 => … case _ => … }

switch(n) { case 1 : … break; case 2 : … break; default : … break; }

if文(式)は値を返す val x = 1 + (if (true) 3 else 4) ->x : Int = 4

for文(式)も値を返せる val list = for(i <- 1 to 10; if i % 3 == 0) yield i ->list = Vector(3,6,9)

Page 6: 15分でざっくり分かるScala入門

Scala早見表 関数

6

Scala Java

def public

private def private

Unit void

return(省略可) return

コンパニオンオブジェクトで代用 static

override @Override

(arg0 : Type0, arg1 :Type1) => { … } (Type0 arg0, Type1 arg1) -> { … }

tlist : Type* Type… tlist

def inc(x : Int): Int = x + 1 private def positive(ls : List[Int]):List[Int] = { ls foreach { print(_) } ls filter (i => 0 < i) }

Page 7: 15分でざっくり分かるScala入門

Scala早見表 オブジェクト指向

7

Scala Java

class class

abstract abstract

trait(ただし実装を持てる!) interface

final final

extends extends

with implements

[A] <A>

[A <: B] A extends B

[A >: B] A super B

package package

import import

これくらい分かれば、ざっくりScalaは書ける

Page 8: 15分でざっくり分かるScala入門

フィボナッチ数列

8

0, 1, 1, 2, 3, 5, 8, 13, …

0と1から始まって、あとは前の2つを足してできる数列

関数型プログラミングの入門でおなじみ

ヒマワリの種のつきかたとかが フィボナッチ数列らしい

Page 9: 15分でざっくり分かるScala入門

Javaっぽい実装

9

def fib(n : Int): BigInt = { if (n <= 0) return 0 if (n == 1) return 1 var n1 = BigInt(0) var result = BigInt(1) for(i <- 2 to n) { val tmp = result result += n1 n1 = tmp } return result }

これはn-1番目

これを n番目 とすると

これはn-2番目

可読性 ?、 実行速度 ○

実行すると for(i <- 0 to 100) print(fib(i)+",") ->0,1,1,2,3,5,8,13,21,34,55,…

Page 10: 15分でざっくり分かるScala入門

関数型っぽい実装

10

def fib(n : Int): BigInt = n match { case n if n <= 0 => 0 case 1 => 1 case _ => fib(n - 1) + fib(n - 2) }

fib(100) -> 終わらない

可読性 ◎、 実行速度 ×

nが0以下の場合ここにマッチ

nが0以下でも1でもないなら、前2つを足したもの 数学的な定義そのまま!

Page 11: 15分でざっくり分かるScala入門

末尾再帰

11

def fib(n : Int): BigInt = { if (n <= 0) return 0 def rec(i : Int, n1 : BigInt, result : BigInt):BigInt = i match { case i if n <= i => result case _ => rec(i + 1, result, result + n1) } rec(1, 0, 1) }

可読性 ○、 実行速度 ○

関数内で再帰関数を定義

カウンタ

ループを回りきったら即 計算結果を返す

関数に渡す前に計算しておく

varとかvalとかなくてもプログラムは書ける

Page 12: 15分でざっくり分かるScala入門

オブジェクトプログラミング1

12

case class Person(val first_name : String, middle_name : Option[String], last_name : String) { def fullName: String = middle_name match { case Some(md : String) => first_name +" "+md+" "+last_name case None => first_name+" "+last_name } def marryWith(person : Person): Person = new Person(first_name, person.middle_name, person.last_name) }

Option型:nullの可能性がある値を包むモナド

caseクラス:equals()やhashCode()などを自動で作ってくれる

Page 13: 15分でざっくり分かるScala入門

オブジェクトプログラミング2

13

object Person { def apply(first_name : String, last_name : String): Person = new Person(first_name, None, last_name) def sasakiFamily(first_name : String): Person = new Person(first_name, None, “Sasaki”) } val mika = Person.sasakiFamily(“Mika”)

コンパニオンオブジェクト:ここに定義された関数はstatic

ファクトリーみたいなもの

Page 14: 15分でざっくり分かるScala入門

オブジェクトプログラミング3

14

val taro = Person.sasakiFamily("Taro") val hana = Person("Hana", "Tanaka") println(hana.fullName) val sasaki_hana = hana marryWith taro println(sasaki_hana.fullName) ->”Hana Tanaka” “Hana Sasaki”

. とか () とか省略できる

Page 15: 15分でざっくり分かるScala入門

15

Javaっぽく設計

関数型っぽく中身を実装

あとは

これでざっくりScala書ける

Page 16: 15分でざっくり分かるScala入門

Javaには無い機能

16

Page 17: 15分でざっくり分かるScala入門

クロージャ

17

def labelMaker(str : String): Unit => String = { var i = 0 Unit => { i += 1 str + i }} val argMaker = labelMaker("arg") for(i <- 1 to 3) print(argMaker()+",") ->arg1,arg2,arg3,

戻り値の型が関数

引数で与えられた文字列

クロージャ内に保存されている変数 この 関数が 帰る

Page 18: 15分でざっくり分かるScala入門

クロージャでフィボナッチ

18

def fib(n : Int): BigInt = { val memo ={ var n1 = BigInt(1) (x : BigInt) => { var tmp = n1 n1 = x tmp }} var result = BigInt(0) for(i <- 1 to n) result += memo(result) result }

引数で与えられた数を保存し、 前回保存した数を返す関数

Page 19: 15分でざっくり分かるScala入門

関数の部分適用

19

def sandwich (header : String)(fooder : String)(body : String): String = header + body + fooder def htmlMaker(tag : String)(body : String): String = sandwich("<" + tag + ">")("</" + tag + ">")(body) val commentout = sandwich("<!-- ")(" -->")_ val ptag = htmlMaker("p")_ println(commentout(“here is a text ")) List("hoge","goo","foo") map ptag foreach print -><!– here is a text --> <p>hoge</p><p>goo</p><p>foo</p>

3つ目の引数はまだ与えない

後から3つ目の引数を与える

何度でも使える

引数のカッコを区切る

Page 20: 15分でざっくり分かるScala入門

部分適用でフィボナッチ

20

def fib(n : Int): BigInt = { def add(n1 : BigInt)(n2 : BigInt): BigInt = n1 + n2 def rec(i : Int, add_memo : BigInt => BigInt, result : BigInt): BigInt = i match { case i if n <= i => result case _ => rec(i+1, add(result), add_memo(result)) } rec(0, add(BigInt(1)), BigInt(0)) }

個人的にはこれが一番かな?

数をとってresultを足す関数

覚えていた数にresultを足す

Page 21: 15分でざっくり分かるScala入門

暗黙の型変換

21

class ExtString(val str: String) { def -(str2 : ExtString): ExtString = new ExtString(str.replace(str2.str, "")) def *(str2 : String): List[String] = for(s <- this.allSubstring; t <- new ExtString(str2).allSubstring) yield s + t def allSubstring: List[String] = { … } override def toString(): String = str } object ExtString { implicit def string2ExtString(str : String) = new ExtString(str) } import ExtString._ println("hoge" - "og") "wnzk" * "a" filter(_.length == 2) foreach {print(_)} ->”he” “ka””na””za””wa” リテラルを自由に拡張できる!

Stringには – や * など無い

ExtStringにはあるから、 StringからExtStringへ変換する 変換規則を定義しておけばいい

文字列の全通りの組

Page 22: 15分でざっくり分かるScala入門

無限リストでフィボナッチ

22

lazy val fib: Stream[BigInt] = Stream.cons(0, Stream.cons(1, fib.zip(fib.tail).map(p => p._1 + p._2)))

(0,1,1,2,3,5,8,…

無限リスト

(1,1,2,3,5,8,…

((0,1),(1,1),(1,2),(2,3),(3,5),(5,8),…

zip

タプルの要素を足す

(1,2,3,5,8,13… フィボナッチ数列

Page 23: 15分でざっくり分かるScala入門

ちなみに ベンチマーク

23

1,000 10,000 100,000 500,000

Javaっぽい 5 20 223 4415

末尾再帰 3 4 182 4501

クロージャ 4 8 186 4401

部分適用 2 6 187 4703

無限リスト 28 69 OutOfMemoryError OutOfMemoryError

-Xmx 1024 -Xms 1024 でfib(n)を計算するのにかかる時間(ミリ秒)