Scala勉強会
Scalaとのであい
あの忌まわしい「Haskell勉強会」から1年
あのとき感じた関数型言語に対する
激しい敗北感
そんなとき耳にした、少しだけフレンドリー
そうな関数型言語
Scalaとのであい
え、なんかJavaと似てるらしい?
モナド?圏論?そんなの関係ねえ?
悪Javaみたいに書けばおk?
これは…
Scalaとのであい
、、、,.
,._
>>Scalaくん……
Scalaくん………
ィ`‘′
ヽ
〃/ノノ八レレ、.
|
Scalaくんに託すっ…!
ル三’‘′`三ヽ. |
[ ≧|ニ|≦_]~|^)ト、
虫のいい話なんだが……
.
| ,-L__」
-、u |ト:|
|’‘‐-
...__
_..
-┬|l王l王l王l`/ .|
| |
Haskellの代わりに…
.
∧
|├‐┬─‐’‘′/
||
ぼくをきたえあげて……
/
l
|.l-―|、___/-―┤
| ̄ ̄|.| | | ヽ. /
| |
関数型をわからせてやってくれ…
/.|
| l. | |
Y。
| |
\/~三三..l
| ̄ ̄ ̄ ̄ ̄
 ̄|
たのむ……
/、
丁` /ヽ「|
/.|
|
.
/
へ、./
| l. /⊿
|_
|
/
|/
| |. └‐::┐r‐┘
.|
. ! /
|_|.
└'
|==
もくじ
Scalaの概要
JavaからScalaへ
Real World Scala
Scalaの概要
Scalaの作者
Martin Oderskyもともと、Javaバイトコードに変換される関数型言語を開発
javacやJava-Genericsに取り込まれる
制限なしで一からミニマムな言語を作ってみた
使う人にとってはあまり嬉しくないことがわかった
Scalaの開発を開始
目標は変わらずOOとFunctionalの統合
開発者が使いやすいように
Scalaのコンセプト
オブジェクトパラダイムと関数パラダイムを統合したマルチパラダイム言語
関数パラダイム
不変な値
関数中心
合流性
参照透明性
再帰
オブジェクトパラダイム
可変な値
オブジェクト中心
多態性
継承
統合(?)
Scalaの実装
Javaバイトコードを生成するScalaコンパイラ+Scala標準ライブラリ(JAR)群
Scalaソースコード
Javaバイトコード
scala-library.jar
Scalaコンパイラ
Scalaの実装
ゆえに(?)Java Scalaの相互呼び出しが可能
object ScalaToJavaCallSample extends Application {def method = println("Hello, Scala!")new JavaToScalaCallSample().method()
}
public class JavaToScalaCallSample {public void method() {System.out.println("Hello, Java!");
}public static void main (String[] args) {
ScalaToJavaCallSample.method();}
}
Scalaの実装
Java -> Scala呼び出しの場合には、ある程度コンパイラの挙動を把握しておく必要あり
変数
すべてメソッドに
クロージャFunctionクラスに
などなど
動作プラットフォーム
Java VM.NET Frameworkそして、、、
Android
Scalaの捉え方
1. OO言語としてのScala2. 関数型言語としてのScala3. 並列処理基盤としてのScala
OO言語としてのScala
というか、Better JavaとしてのScala“すべてがオブジェクト”
記法の簡略化
“Singleton”の言語レベルサポート
Mix-Inの導入
型推論の広範な導入
暗黙的な引数/型の補完・変換
擬似ダックタイピング
ネストされたメソッドの導入
関数型言語としてのScala
高階関数
ラムダ式
クロージャ
Yコンビネータ
カリー化
遅延評価
不変オブジェクトだらけの標準ライブラリ
パターンマッチ、Caseクラス
並列処理実行基盤としてのScala
Future並列計算
セマフォ
Reader/Writer同期/非同期チャネル
WorkersMailboxesActors
JavaからScalaへ
すべてがオブジェクト
プリミティブ型消滅、Scala独自のクラス群に
scala.Int, scala.Long, …内部的にはプリミティブ+俺Boxingで処理
関数/メソッドもオブジェクトに(後述)
Function0~クラス
演算子はすべてメソッドに
メソッドも演算子のように使える
記法の簡略化
例:クラス定義(Java)
public class Foo {private String name;public Foo(String name) {
this.name = name}public void setName(String name) {
this.name = name}public String name() {
return name}
}
記法の簡略化
例:クラス定義(Scala)
class Foo (var name: String)
objectの導入
要するに「Singletonなclass」staticの代替と考えてもおk
コンパイル後には実際、static+Singletonクラスに
classとは異なる名前空間を持つ
Scalaライブラリの中で、classと同名のFactoryとしてリテラルの拡張のような形で使われている
object HelloWorld extends Application {println(“Hello, World!”)
}
val list : List = List(1, 2, 3, 4, 5)
Mix-In
特定のプログラム要素(trait)をclassに付加可能
traitは実装を持つインタフェースのように振舞う
Javaのインタフェースは存在しない
class A extends B with Ctrait B
trait C
自分のイメージはなんかこんなかんじ
Mix-in
Traitの例
trait HelloTrait {val msg = "Hello, World!"def say {println(msg)
}}class SimpleClass extends HelloTraitnew SimpleClass().say
Mix-Inの正体
コンパイラは、このようなバイトコードを生成
class A extends B { trait B {
class A implements B { interface B {
abstract class B$class {
def method {…
public void method();
public void method {B$class.method();
}public static void method {
println(“hello, world!”);}
実装
委譲
型推論
型を明記しなくてもコンパイラが推測、補完
一番簡単な例
推測できない場合や、矛盾が見つかった場合にはエラー吐いてくれる
val obj: SampleClass = new SampleClass
val obj = new SampleClass
型推論
もうちょい凝った例:
dupはこのような形で呼び出し可能
自分は、どこでなら型推論が働くのか、あまり把握できてません。コンパイラの奴隷です。
def dup[T](x: T, n: Int): List[T] =if (n == 0) Nil else x :: dup(x, n - 1)
dup(“three”, 3)推測
implicit
暗黙的にメソッド引数を補完
引数が足りなくても、implicit宣言した値を探し出してきて勝手に補完してくれる
def method[A](x: List[A])(implicit y: Param[A]) {println(x); println(y)
}abstract class Param[A]implicit object IntParam extends Param[Int]implicit object StringParam extends Param[String]
method(List(1,2,3)) <= IntParamを補完method(List(“a”, “b”, “c”)) <= StringParamを補完
implicit
暗黙的に型変換(というより、型をラップ)
C#の拡張メソッドのようなことができる
class Factorizer(x: Int) {def fact(n: Int): BigInt =
if (n == 0) 1 else fact(n-1) * ndef ! = fact(x)
}implicit def int2fact(n: Int) = new Factorizer(n)println(10!)
擬似ダックタイピング
Structured Typesという機能で可能に
「def close : Unit」をメンバに持つオブジェクトであればなんでもOKもちろんここでも(r: R)から型推論される
def method[R <: {def close : Unit}](r: R) = { …
ネストしたメソッド
メソッド内にメソッドを定義可能
定義されたメソッドは、外側のメソッドのローカル変数を参照できる
カリー化や、その他高階関数で使ったりする
def outer {val innervalue = “hello.”def inner() = {println(innervalue)
}inner()
}
高階関数・匿名関数
関数を返す関数や、関数を引数に取る関数
クロージャ、カリー化の基盤になる
無名関数も作ることが出来る
例:有名なやつ
xs map (x => x * x)
abstract class List[A] { ...def map[B](f: A => B): List[B] = this match {case Nil => thiscase x :: xs => f(x) :: xs.map(f)
}
カリー化
関数の引数を部分的に渡すことで、引数が部分的に適用された関数を作ることができる
関数内でバリエーションを扱える
関数をカリー化可能な形式にする必要あり
def func(x: Int, y: Int, z: Int): Int = {x + y + z}
def func(x: Int)(y: Int)(z: Int): Int = {x + y + z}
Function.carried(func _)(func _).carry
カリー化
簡単な例:
val newfunc = func(1)(2)newfunc(3) // => 6Newfunc(5) // => 8
遅延評価
Scalaでは、引数の評価タイミングを選ぶことが出来る
Call by Value(Javaとか)
def func(x: Int) =…
Call by Name(Haskellとか)
def func(x: => Int) =…呼び出される側には、未評価のブロックが渡ってくる
関数渡しdef func(x: () => Int) = …関数がわたってくる
実質的にはCall by Nameと同じ
遅延評価
変数初期化式の評価タイミングも選べる
lazy val = DB.hogeTable.selectAllvalが 初に評価されるまで、SELECTは行われない
フィボナッチ数列の無限リスト
lazy val fib: Stream[Int] =Stream.cons(0, Stream.cons(1,fib.zip(fib.tail).map(p => p._1 + p._2)))
モナド
List、Stream、Map、Optionなどはモナドとして構成されている
For-ComprehensionはList内包表記ではなくモナド操作用構文
For-Comprehensionが正常に動作するためには
map[B] (f: A => B) : M[B]flatMap[B] (f: A => M[B]) :M[B]unit[A] : M[A]
これらが存在し、モナド則(Monadic Law)を満たす必要がある
Real World Scala
AOP
traitを使うことでそれっぽいことが実現可能
インスタンス単位でtraitを付加できることを利用する
内部的には、traitを付加したインスタンスごとに個別にクラスを生成している
DIと組み合わせれば効果的なのはJavaと同じ
実行時に織り込むタイプのAOPフレームワークも使える
val enhanced = new Target with AroundAdvice
DI
Mix-InとSelf-Type Annotationでそれっぽいものが実現可能
Self-Type Annotationとは、Mix-inされ、インスタンス化される際の型を指定できる機能
既存のDIコンテナも使えるけど、相性もあるScalaだとフィールド定義できないとか
setter/getterがスタイルにあわないとか
trait SomeTrait {this: SomeClass =>…
ライブラリ
Scala-Library不変コレクション
Actorパーサコンビネータ
…
Actorモデル
動作モデル
scala.actorsパッケージでこのモデルをサポート
Actor
Actor
create
Actor
send async messages
send async messages
address
address
addressM
M
M
M
なんかこんなかんじ詳しく知りたければWikipediaにリンクされてる論文読んで
共有領域は持たない必要な情報はメッセージで
scala.actors
scala.actors.Actor
M
mailboxMM
Actorオブジェクト
act
処理M
send
Actorフレームワーク
ThreadとActorの関係
Actorオブジェクトに割り当てられる「わけではない」
メッセージ駆動の処理に「都度」割り当てられる
M
mailboxMM
Actorオブジェクト
act処理M
send
Actorフレームワーク
Threadの割り当てはSchedulerが行う
M
mailboxMM
Actorオブジェクト
act処理M
Scheduler
send
Actorフレームワーク
スレッド依存版(receive/wait)Thread
mailbox メッセージ取得
M
メッセージなし
ブロック!
Actorフレームワーク
スレッド非依存版(react)Thread
mailbox 1. メッセージ取得
M
メッセージなし
2. 処理保存
3. 例外スローにより終了
処理
Actorフレームワーク
スレッド非非依存版(react)Thread
mailbox
4. メッセージ取得M
Thread
send
3. 再開
処理2. 処理取得5. 処理実行
1. 送信
【恒例】デモ「悟空vsフリーザ」【行事】
悟空とフリーザを戦わせてみた
VSKorea Japan
パーサコンビネータ
Scala標準の構文解析ライブラリ群
字句解析してくれるあたり
expr ::= term {'+' term | '-' term}term ::= factor {'*' factor | '/' factor}factor ::= floatingPointNumber | '(' expr ')'
object ArithParser extends JavaTokenParsers {def expr: Parser[Any] = term ~ rep("+"~term | "-"~term)def term : Parser[Any] = factor ~ rep("*"~factor | "/"~factor)def factor : Parser[Any] = floatingPointNumber | "("~expr~")“def parse(text : String) = { parseAll(expr, text) }
}
ライブラリ
Scala-DbcScalaでSQLライクに書けるモノらしい
ドキュメント皆無 Webにも情報皆無
評判悪
ライブラリ
Scala-SwingScala標準ライブラリの1つ
デフォルトのアプリケーションモデルを提供基本的な画面構造をあらかじめ定義
(Simple)GUIApplication
イベントモデルの修正Event Publisher/Subscriberイベントハンドラが色んなコンポーネントを知らなくて良い
Swingを利用したプレゼンテーション用言語内DSLとも見ることができる
リテラルライクな画面構築
ちょっとだけ宣言的に書いている気になれる
ライブラリ
Scala-Swingobject SwingApp extends SimpleGUIApplication {
def top = new MainFrame {title = “SwingApp”; var numclicks = 0object label extends Label {
text = “Number:” + "0 "listenTo(button)reactions += {case ButtonClicked(button) =>numclicks = numclicks + 1text = “Number:” + numclicks
}}object button extends Button { text = "I am a button" }contents = new FlowPanel { contents.append(button, label) }
}} Scala勉強会@札幌より引用
フレームワーク
LiftServletで動作するフルスタックWebフレームワーク
Railsライクな開発スタイルMaven2のプラグインで実現
内部はRailsと同じく黒魔法、実際の学習コストは高め
非同期系のサポートAjaxサポート、jQuery同梱
ActorによるCometのサポート
共通機能SiteMapやACLの組み込み
設定はコードで
フレームワーク
LiftView
XMLリテラルによるViewの記述
ControllerではなくView中心、ViewHelperの組み合わせみたいな感じ
ORMARみたいな標準ORMあり
Djangoとかいうのに似た機能もあるらしい
フレームワーク
Liftのアーキテクチャ
LiftFilter
LiftServlet
Boot
LiftRules
http://liftweb.net/index.php/How_lift_processes_HTTP_requests
登録
early
フック
URLリライト
RequestState
呼び出し
生成
Snippet Model
TemplateXHTMLS
Model
dispatch
Snippet
REST
Comet
Ajax
LiftSession
フレームワーク
Form仕様は意味不明
Menu画面 1-1./form.html
Lift
form.html
1-2.refer
input text
submit
show Snippet
Form画面
Lift2-1.submit
Handler
1-4.register
2-2.execute2-4.instanciate
show Snippet
2-3.値取得
1-3.instanciate
フレームワーク
Liftざっとさわってみて
レイヤの感覚は希薄、model.toFormがHTMLタグ返す
APIが直感的ではないAjax、CometはまぁOKFormが使いづらすぎる
ドキュメントなさすぎ、古すぎ
新のScalaに対応してない(2008.11.21現在)
フレームワーク
Web Flavorぶっちゃけて言えば、Scala版JSPServlet/JSPコンテナ上のScala(Java)アプリとしてJSPコンテナを実装しているようなイメージ
XMLリテラルでPHP的なテンプレートエンジンを構成
リクエスト発生時にScalaソースコードをコンパイルして実行、表示
フレームワーク
Web FlavorPOHPでHTMLテンプレート的な構成も可能に
<span flavor:id=“xxx”>
事前に全コンパイルし、通常のJavaWebアーカイブとしても配布可能に
手軽にWebアプリを作るには結構便利
XMLリテラル以外にScalaっぽい要素は少ない
補:SAStruts
出来心で使ってみた。
CoC的なFWはラップしないと使いづらい
Scalaコンパイラが生成するバイトコードのスタイルはScalaプログラムが直接コントロールできないため
フレームワークにあわせようとするとScala的なプログラミングスタイルから逸脱する
Scalaプログラミングスタイルにあわせるとフレームワークが動かない
Scalaのよさそうなところ
簡略記法による軽量な開発
副作用排除による品質の向上
わりと速い(Javaとあまりかわらない)
Javaとの相互運用性は高い
Scala=>Javaはほぼ問題なし
Java=>Scalaは注意が必要
Better Javaとして使うには十分なレベル
Actorその他で並列処理が得意
並列処理のAP基盤開発には良さげ
Scalaのよさそうなところ
DSLが作りやすそう
言語機能との区別がつきづらいような記述が可能
リテラルもどき
制御構文もどき
Caseクラス
パーサコンビネータ
Scalaのなんかいまいちなところ
開発環境はイマイチ
Eclipseプラグインはエラーの嵐、Javaレベルは遠い
Scalaの長所を生かしきったFWが少ない
関数型のわかりづらさとカオスな言語仕様があいまって、読めない人続出の予感
もう意味がよくわからない例
Scalaの制御構文?
object TargetTest2 extends Application {var i = 10loop {println("i = " + i) i -= 1
} unless (i == 0)}
もう意味がよくわからない例
いいえ、メソッドです。
object TargetTest2 extends Application {def loop(body: => Unit): LoopUnlessCond =
new LoopUnlessCond(body)protected class LoopUnlessCond(body: => Unit) {
def unless(cond: => Boolean) {body if (!cond) unless(cond)
}}
}
なぜそうなる
List構築の際の一般的な書き方
これは何?Listクラスの特別な構文か何か?
val list = List(“First”, “Second”, “Third”)
なぜそうなる
いいえ、Listオブジェクトです。
object List {def apply[A](xs: A*): List[A] = xs.toList
…sealed abstract class List[+A] extends Seq[A] {…
なぜそうなる
Streamを構築する際の一般的な書式は
Streamクラス?いやいや、違うはず。
Streamオブジェクトのconsメソッドだよね。
Stream.cons(1, Stream.cons(2, Stream.Empty))
なぜそうなる
Streamオブジェクトの内部オブジェクトである「cons」のapplyメソッドです。
object Stream {object cons {
def apply[A](hd: A, tl: => Stream[A]) =new Stream[A] {override def hasDefiniteSize =
if (tlDefined) tlVal.hasDefiniteSizeelse super.hasDefiniteSize
…}
言語内DSLへの道
このようなよくわからない構文を使うと、言語内DSLへの道が開けます
implicitもあわせると効果抜群、意味不明
val con = new FooConnectionusing(con) { c =>c.doSomething
}
さわってみた印象
しょせんJavaだから
とか思ってなめてかかると痛い目にあう
というか意味がわからなくなるなった
さわってみた印象
JavaScriptやRubyを超える
カオスさに好印象
ありがとうございました
何か質問があれば