unoh.github.com

5分くらいで知るScala

2008-10-27 01:43:12 +0000

はじめまして。今月入社した内田です。
以前は業務系のSI会社に勤めていたので、Web系という畑の違う環境に少々戸惑うこともありますが、最近少しずつ慣れてきました。
今回は先日、社内勉強会でやった「Scala」について5分くらいで紹介したいと思います。

Scalaとは


関数型言語とオブジェクト指向言語の特徴を統合したマルチパラダイム言語です。
主にJavaVM上で動作し、他にも.NET Framework、Google Android等でも動作が確認されています。そしてJavaや.NET等の既存の豊富なライブラリを使用することが可能です。
このあたりはwikipediaに詳しく書かれています。

Wikipedia:Scala


約1年程前には日本でのScala人口は1桁とも言われていましたが、最近では各地で勉強会が開催される等盛り上がりをみせ、「次の言語」として注目されています。個人的にScalaの魅力は前述した豊富なライブラリを使用できることと、スクリプト言語としての簡単な構文、そしてマルチコアに対応したアプリを簡単に記述できるActorの存在が大きいと思います。

すでに1分近くたってる様な気がするのでサクサクとコードを紹介します。

Hello World!


まずはプログラミングの基本「Hello World!」
object HelloWorld {
    def main(arg:Array[String]) = {
        println("Hello World!")
    }
}

上記の様にobjectキーワードを使うことでアプリケーションを実行することができます。
このコードを「HelloWorld.scala」として保存し
$ scalac HelloWorld.scala
$ scala HelloWorld

で実行されます!
またscalaを引数無しで起動すると対話的に実行することができます。以下は全て対話的に行っています。

文法


Scalaは文法的にかなり曖昧な書き方もできてしまうので、全てを紹介することはできませんが、基本的な部分をサラッと紹介します。

変数


関数型的な「val」と手続き指向的な「var」
val i = 1
var i = 1
val i:String = "hello"
var i:String = "hello"

制御構文


if文(javaなんかと一緒)
if (a == b) {
    println("一緒")
} else {
    println("違うよ")
}

ループ。foreachのようなもの。
val l = List(1, 2, 3, 4, 5)
for (n <- l) {
    println(n)
}

10回ループしたかったら
for (n <- 1 to 10) yield println(n)

パターンマッチ switch caseの拡張版
_はその他
val name = "tarou"
name match {
    case "tarou" => println("nice to meet you")
    case _ => println("how are you")
}

関数


関数の基本的な書き方
def 関数名(引数:引数型):戻値型 = { 処理 }
def hello(name:String):String = {
    "hello, " + name
}
hello("tarou")

クラスとメソッド


クラス定義


ほとんどJavaと同じですね。
thisはコンストラクタのオーバーロード。
private宣言しない変数は全てpublicになります。
class Car {
    var name:String = ""
    def this(name:String) = {
        this()
        this.name = name
    }
}
var c = new Car("hello")
c.name

class宣言とコンストラクタを纏めることができます
class Car(var name:String)
var c = new Car("hello")
c.name

メソッド


Unitはvoidと一緒
class Car(var name:String) {
    def move():Unit = {
        println(name + " is moving")
    }
}

一行で書いてもOK
class Car(var name:String) {
    def move = println(name + " is moving")
}

3分くらいたちました。残りの時間で無名関数、カリー化、高階関数といった関数型言語的な内容を紹介します

無名関数、クロージャ


(引数:引数型) => { 処理 }
val l = List(1, 2, 3)
l.map((x:Int) => {
    x * 2
})

無名関数だけではないのですが、引数の型は型推論されるため、省略できる場合が多いです
l.map((x) => { x * 2 })

単一の式の場合{}はいりません
l.map((x) => x * 2)

()もいりません
l.map(x => x * 2)

引数が一つの場合_に代入され、こんな省略もできます
l.map(_ * 2)

クロージャなのでローカル変数を保持します
def add(x:Int) = {
    (y:Int) => x + y
}
val add2 = add(2)
add2(3)

カリー化


複数の引数をとる関数を、引数が「もとの関数の最初の引数」で戻り値が「もとの関数の残りの引数を取り結果を返す関数」であるような関数にすること(wikipediaより)。
関数型言語では基本的な考え方で、Scalaでも構文的にサポートしています。
前述のクロージャと同じ処理を実現していますが、直感的に分かりやすい実装になっています。
複数の引数(x,y)をとる関数を、引数が「x」で戻り値が「引数に「y」を使い結果を返す関数」であるような関数
def add(x:Int)(y:Int) = {
    x + y
}
add(3)(2)
val l = List(1, 2, 3)
l.map(add(3))

余談なのですが、意味が通る範囲内ではメソッドの括弧と.は省略できます
l map add(3)

高階関数


関数を引数にとる関数。
関数を戻り値とする関数。
def calc(x:Int, y:Int, f:(Int, Int) => Int) = { f(x, y) }
def add(x:Int, y:Int) = { x + y }
calc(1, 2, add)

もちろん無名関数も引数にできます
calc(1, 2, (x:Int, y:Int) => { x + y })

カリー化も関数を戻り値とするので高階関数の一種ですね。
_を使うことで関数として代入できます。
def add(x:Int)(y:Int) = x + y
val add2 = add(2)_
add2(3)

まとめ


5分をオーバーしたかもしれませんが基本的な部分を紹介することができました。
Scalaにはまだまだ特徴的な構文が存在し、面白い言語です。今回をきっかけにScalaを一緒に学んでいきましょう!
次回は紹介できなかった残りの文法とライブラリを中心に見ていきたいと思います。

*本文の間違った内容や面白い情報がありましたら教えてください!