Scalaで始める関数型プログラミング入門
なんとなく今更感ではあるものの、ちゃんとやっていきたいなと思ったので備忘録です。
関数型のメリット
- 副作用の排除
副作用とは
ある機能がコンピューターの(論理的な)状態を変化させ、それ以降で得られる結果に影響をあたえることをいう
- 変数への値の代入
- データ構造を直接変更する
- オブジェクトのフィールドを設定する
- 例外をスローする、またはエラーで停止する
- コンソールに出力する、ユーザ入力を読み取る
- ファイルを読み取る、ファイルに書き込む
- 画面上に描画する
純粋関数
副作用を持たない関数
メリット
- 宣言的な記述なため、簡潔に書けることが多く、関数の仕様を理解しやすい
- 副作用がないため、形式的な証明がし易い
- 関数の評価結果がコンテキストに依存しないため、テストがし易い
- コンテキストに影響を与えないため、関数を組み合わせて利用しても相互に影響しない
インストール
scalaenvを使ったインストール
scalaenvのインストール
$ git clone git://github.com/mazgi/scalaenv.git ~/.scalaenv $ echo 'export PATH="${HOME}/.scalaenv/bin:${PATH}"' >> ~/.bashrc $ echo 'eval "$(scalaenv init -)"' >> ~/.bashrc
scalaのインストール
$ scalaenv install -l $ scalaenv install scala-2.11.7 $ scalaenv versions
基本構文
コメント
// コメント /* これもコメント */ /** * コメントです */
セミコロン
セミコロン(;
)は省略可能
変数
var 変数名:型 = 値 型については、型推論であるため省略可能
var num:Int = 1 var str:String = "abc" var short:Short = _ // _で初期値が設定される
定数
val 定数名:型 = 値
val NUM:Int = 1 var STR:String = "abc"
代表的な型
name | description | default value |
---|---|---|
Boolean | 真偽値 | false |
Char | 2byte文字列 | '\0' |
String | 文字列 | null |
Short | 整数(16bit) | 0 |
Int | 整数(32bit) | 0 |
Long | 整数(64bit) | 0 |
BigInt | 任意精度整数 | null |
Fload | 浮動小数(32bit) | 0.0 |
Double | 浮動小数(64bit) | 0.0 |
BigDecimal | 任意精度固定小数 | null |
Symbol | シンボル(文字の前にシングルクォート | null |
制御文
if
if (true) 1 else 2
while
条件式はBoolean型である必要がある
while (true) A
for
for (s <- Array("a", "b", "c")) println(s)
match
他の言語でいわゆる、swich-case文のイメージ
var one = 1 one match { case 1 => println("one") case 2 => println("two") case _ => println("other") }
関数
def 関数名 (引数名 : 引数の型) : 戻り値の型 = {}
def append_ten(num : Int): Int = { return num + 10 }
return
は省略可能で、省略した場合は最後に評価した式の値が戻り値として返される
戻り値の型と{}も省略可能
1行で記述
def append_ten(num : Int) = num + 10
クラス・メソッド
コンストラクタ
// class名(コンストラクタのパラメータを宣言) class User(_name : String) { def name = _name } var user = new User("Tom") println(user.name) // Tom
フィールド
フィールドはvar
かval
で定義する
var
ではsetter/getterの提供、val
ではgetterのみの提供
class User(_name : String, _age : Int) { var name = _name val age = _age } var user = new User("Tom", 23) println(user.name) // Tom println(user.age) // 23 user.name = "Bob" // nameは"Bob"に更新される user.age = 14 // val定義なのでエラーになる
アクセス修飾子と継承
class User(_name: String, _age: Int) { val name = _name val age = _age def agree = println("Hi, I'm " + name) def how_old = println("I'm " + fudge_the_count) protected def real_age = age // protected メソッド private def fudge_the_count = age - 5 // private メソッド } // extendsキーワードで継承 class Profile(_name: String, _age: Int) extends User(_name: String, _age: Int) { // 親クラスのメソッドをオーバーライド override def agree = println("Hi, I'm " + name + ". I'm going to be " + real_age + " this year") } var user = new User("Tom", 42) user.agree user.how_old var profile = new Profile("Tom", 42) profile.agree
オブジェクト
シングルトンオブジェクトの作成 = Javaのstaticと同等の役割
mainメソッド
実行時の処理を実装する
object Obj { def main(args: Array[String]) { println("Hello, World") } }
コンパニオンオブジェクト
クラス名と同じ名前をつけたオブジェクトのこと
共通の操作・処理を扱う
class Sample { } object Sample { }
ファクトリー
class Sample private(a: Int) { protected var n = a } object Sample { def apply(a: Int) { new Sample(a) } } Sample.apply(123) Sample(123)
トレイト(Trait)
機能の実装が行えるインタフェースのようなもの
Javaのインタフェースと同様、mix-inすることが出来る
trait Agree { def en = println("Hello, World") } trait Body { } /* mix-in */ class User extends Agree with Body
タプル(Tuple)
複数のデータを格納できるコンテナ型。違う型でも格納できる。
val t = (1, "abc", 2)
22個までがタプルに格納できる限界数
コレクション
Seq
要素を並べて管理するコレクション
var seq = Seq(1, 2, 3) // 取得 println(seq(0)) // loop seq.foreach { println }
Map
キーを元に値を取得するコレクション
var map = Map("key" -> "val") // 取得 println(map("key")) // 追加 map += ("key2" -> "value")
例外処理
try { func() catch { case e: IOException => ... finaly { }
try, catchはそれぞれ値を返すが、finalyは返さない
Option
Optionは値がない可能性を型で表現している
スレッド
JavaのThread等そのまま使えるが、Actorを使うことが多いらしい