今 Scala IN DEPTH という書籍を読んでいる。
アウトプットがてら、まとめていくことにした。
前提として、この書籍は 2.9.x ベースで書いているみたい。
まずは1章、Scala— a blended languageのまとめ。
In this chapter
- Short introduction to Scala
- Insights into Scala’s design
要約
Scalaは、1つの言語の中に3つの考え方を混ぜている。
- 関数型プログラミングとオブジェク指向プログラミング
- 高度なシンタックスと静的型付け
- 高度な言語機能と、リッチなJava統合
関数型プログラミングとオブジェクト指向プログラミングが出会う
関数型プログラミング
- verbs(動詞)とverbsを結合して扱っていく方法を重要視する。
- bottom-upアプローチ。関数を結合していく。
オブジェクト指向プログラミング
- nouns(名詞)を重要視し、nounsにverbsを結びつける。
- top-downアプローチ。nouns or objectにコードを分割していく。
静的型付けと表現力
- Scalaの型システムは、高度なコードを可能にする。
- Cから派生した静的型付け言語は冗長なコードになると考えられていた。
- コンパイラーは改良されているし、今はそんなことはない。
- Scalaはコード内の定形式を減らし、簡潔さを保つことができる。
Scalaは、以下のような設計をしている。
- type annotation(型注釈)の位置を変える。
- type interface(型推論)
- Scalableシンタックス
- ユーザ定義のimplicits(暗黙)
位置を変える
- Scalaでは変数の右側にtype annotationを置く。
- JavaやC++では、type annotationは変数・戻り値・引数の型を表現するモノ
- Scalaでは、
var
val
lazy val
の3つの変数型を左側に定義する。この3つが変数の型を明確にする。 - 変数の型から、変数自身の振る舞いを分離する
- 変数の右側に型を置いて、変数の型を決定するtype interfaceを許す。
type interface(型推論)
- Scalaは可能な限りtype interfaceを実行する。
- type interfaceは
- ユーザにtype annotationを明確にすることを強制するというよりは、コンパイラがtype annotationが何であるかを決定する時に使われる
- ユーザは常にtype annotationを提供することができるが、コンパイラが実行できるようにするオプションもある。
- Scalaはファーストクラス関数により、メソッドの引数をある程度のレベルで推論することができる。
- もし関数の引数を取る場合は、関数で使用されている型がリテラルであることを推論できる。
冗長なシンタックスの削除
- Scalaのシンタックスは、コードの1行が簡単な場合は、冗長なシンタックスを削除することができる。
リファクタリング前
def qsortT <% Ordered[T]:List[T] = {
list.match({
case Nil => Nil;
case x::xs =>
val (before,after) = xs.partition({ i => i.<(x) });
qsort(before).++(qsort(after).::(x)));
});
}
> (Joshua D. Suereth, Scala in Depth, p.9)
> ```:リファクタリング後
def qsort[T <% Ordered[T]](list:List[T]):List[T] = list match {
case Nil => Nil
case x :: xs =>
val (before, after) = xs partition ( _ < x )
qsort(before) ++ (x :: qsort(after));
}
(Joshua D. Suereth, Scala in Depth, p.9)
セミコロン推論
- メソッドを呼ぶ前の
.
のようなシンタックスを放置しない限りは、コンパイラは行の終わりが式の終わりと仮定する。
演算子表記
- 演算子表記は、Scalaがメソッドを演算子として扱えるようにする
- 引数なしのメソッドは、後置演算子として扱える
- 1引数のメソッドは、中置演算子として扱える
- メソッド呼び出しの順序を逆にする、メソッド名の最後につける特定の文字(例、
:
)のための特別ルールもある
x.foo(); /is the same as/ x foo
x.foo(y); /is the same as/ x foo y
x.::(y); /is the same as/ y :: x
> (Joshua D. Suereth, Scala in Depth, p.10)
### プレースホルダ
- 匿名関数(lambda)を定義する時に、プレースホルダ表記を提供する。
- `_`キーワードを関数引数のプレースホルダとして使う。
- 複数のプレースホルダを使う場合は、連続したプレースホルダは関数リテラルに連続した引数を参照する。
- プレースホルダ表記は単純な関数のために予約されている。
## Implicitsは古い概念
- Implicits(暗黙)は自体は昔からある概念だけど、Scalaでは新しい解釈をしている。
- 暗黙的な型変換の概念を初めて導入したのは、C++言語でprimitive型。
- 例えば、`long`の値を宣言する時に、値の損失なしで`int`リテラルを使える。
- 型`double` `float` `int` `long` はコンパイラーによって異なる。
## ScalaのImplicitキーワードを使う
- implicitsは、必要に応じてある型から別の型に自動で変換するために使用している。
- implicitsを使用するには、以下の方法でレキシカルスコープに関連付ける必要がある
- コンパニオンオブジェクトを介す
- 明示的にインポートする
### `implicit`キーワード
- スコープ観点だと、自動的に渡される引数を特定して作成するために使われる
- APIの特定の機能を、レキシカルスコープのために使用することができる
- implicitsのlookupポリシーは継承の線形なので、メソッドの戻り値の型を変更するために使用することができる
- この例はCollections API。詳細は7章
- ある型から別の型に自動で変換するために使われる
- 関数にパラメータを渡す時に発生する。
- 異なる型が必要であると検出すると、型階層をチェックしてパラメータに適応するためのimplicit conversionを検索する。
- メソッドが特定の型に対して呼ばれた時も発生する。
- 目的のメソッドが見つからない場合は、メソッドを含んだ型を見つけるか、implicits conversionできなくなるまで探し続ける
## JVMで動かす
JavaとScalaを共存させて使う話なので、省略。
## Summary
- この章で、Scalaの哲学を学んだ
- 他の言語の様々なコンセプトを混ぜている
- 関数型プログラミングとオブジェクト指向プログラミングを混ぜている
- 冗長性を減らすシンタックスを選択できる
- type inferenceのようなエレガントに表現する強力な機能を可能にする
- Javaと統合できる
# 所感
- Scalaの特徴的なことを述べている。
- implicitsがピンとこない。7章で説明すると言っているので、そこで詳細を追ってみる。
- 簡潔に書ける方法が豊富なのは嬉しい。