のんびりSEの議事録

プログラミング系のポストからアプリに関してのポストなどをしていきます。まれにアニメ・マンガなど

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

フィールド

フィールドはvarvalで定義する
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は値がない可能性を型で表現している

ScalaのOptionとEitherで例外処理を行う方法

スレッド

JavaのThread等そのまま使えるが、Actorを使うことが多いらしい

Scalaでアクター!

参考文献