WHAT'S NEW
CONTENTS
お気楽 Scala プログラミング入門と Yet Another Scala Problems のフォントを Web フォント (Noto Sans JP, Noto Sans Mono) に変更し、印刷用の CSS を追加しました。Web ブラウザの印刷機能を使って PDF に変換することもできます。表示が崩れるときはフォント Noto Sans Mono CJK JP をインストールしてください。
お気楽 Scala プログラミング入門
CONTENTS
●入門編
- 2024/12/17 Scala の基礎知識
使ってみよう、整数と浮動小数点数、算術演算子、比較演算子、論理演算子、文字と文字列、変数、条件分岐、while による繰り返し、for による繰り返し、FizzBuzz 問題、オブジェクト指向の簡単な説明、実行結果、素因数分解、数値積分 (πの計算)
- 2024/12/17 Scala の基礎知識 (2)
関数の基礎知識、関数の定義方法、局所変数と大域変数、局所変数の定義と有効範囲、整数の和、局所関数の定義、累乗の計算、配列、統計量の計算、素数を求める、エラトステネスの篩、値呼びと参照呼び、可変長引数、デフォルト引数、名前付き引数
- 2024/12/17 再帰定義
再帰定義の基本、再帰定義のポイント、ユークリッドの互除法、フィボナッチ関数、末尾再帰、二重再帰を末尾再帰に変換する、末尾再帰を繰り返しに変換する、相互再帰
- 2024/12/17 高階関数
関数を引数にとる関数、多相性、データの探索、無名関数、カリー化、部分適用、関数の合成
- 2024/12/17 リスト
リストの構造、リストの生成と参照、リストの合成と分解、再帰定義によるリスト操作、リストの連結、リストの反転、リストの探索、Option、タプル (Tuple)
- 2024/12/17 パターンマッチング
val や var でのパターンマッチング、match 式、リストのパターンマッチング、Option のパターンマッチング、連想リスト、挿入ソート
- 2024/12/17 高階関数 (2)
マッピング、プレースホルダー、フィルター、畳み込み、畳み込みの使用例、foreach、for 内包表記、クイックソート、クイックソートの弱点、リストの平坦化
- 2024/12/17 レキシカルスコープとクロージャ
レキシカルスコープ、レキシカルスコープと局所関数、クロージャ、環境の仕組み、ジェネレータ、イテレータ
●オブジェクト指向編編
- 2024/12/20 オブジェクト指向の基礎知識
オブジェクトとは?、クラスとインスタンス、メソッド、継承、Scala のクラス、Scala のインスタンス、Scala のメソッド、コンストラクタ、補助コンストラクタ、メソッドの多重定義、Point クラス、toString メソッド、equals メソッド、シングルトンオブジェクト、コンパニオンオブジェクト、apply, unapply メソッド、case クラス
- 2024/12/20 継承
単一継承、多重継承、継承の仕組み、単一継承の使い方、オーバーライド、型の継承、継承とオーバーライドの制限、抽象クラス、図形のクラス、キャストとポリモーフィズム
- 2024/12/20 トレイト
トレイトとは?、多重継承とその問題点、Mix-in、トレイトの使い方、図形のクラス、Ord トレイト、クラスからトレイトへのキャスト
- 2024/12/20 連結リスト
可変 (mutable) な連結リスト、連結リストの定義、作業用メソッド _nth、データの参照、データの更新、データの挿入、データの削除、連結リストの表示、実行例 (1)、マッピング、データの探索、フィルター、畳み込み、実行例 (2)、不変 (immutable) な連結リスト、メソッドの定義、実行例 (3)、高階関数の定義、実行例 (4)
- 2024/12/20 二分探索木
木構造、二分木、節の定義、データの探索、データの挿入、データの削除、最小値と最大値、データ削除のプログラム、巡回 (traverse)、二分木の畳み込み、public メソッドの作成、実行例 (1)、不変 (immutable) な二分木、メソッドの定義、実行例 (2)
- 2024/12/20 例外処理
例外の捕捉、try 式の使い方、例外の送出、例外の定義、大域脱出、finally 節
- 2024/12/20 多相クラス
クラスの型パラメータ、双方向リスト、双方向リストの仕様、クラスの定義、データの参照、データの更新、データの挿入、データの削除、実行例、制限付きリスト、スタック、継承は is-a 関係を表す、mutable なスタックの実装、キュー、mutable なキューの実装
- 2024/12/20 多相クラス (2)
抽象型とは?、スタックの仕様、リストを使ったスタックの実装、配列を使ったスタックの実装、リングバッファ、キューの仕様、配列を使ったキューの実装、簡単な実行例、immutable なスタックの実装、immutable なキュー、immutable なキューの実装、型パラメータの制限 (上限境界と下限境界)、Ordered トレイト、変位の指定 (非変、共変、反変)、mutable な多相型データ構造は非変
- 2024/12/20 多相クラス (3)
Option の定義、不変 (immutable) で多相的な連結リスト、メソッドの作成、実行例、暗黙のパラメータ、不変 (immutable) で多相的な二分木、メソッドの作成、実行例
- 2024/12/20 入れ子クラスとイテレータ
入れ子クラスとは?、内部クラス、無名クラス、抽象クラスとトレイトからインスタンスを生成する、イテレータ、双方向リストの改良、実行例
●応用編
- 2024/12/23 パッケージ
パッケージの宣言、パッケージの入れ子、一つのファイルに複数のパッケージを定義する、import 文、import 文の便利な機能、オブジェクトのインポート、パッケージオブジェクト、スコープ限定子、シールドクラス
- 2024/12/23 有理数
有理数の定義、有理数の生成、算術演算子の定義、暗黙の型変換、変換関数の定義、比較演算子の定義、その他のメソッド、小町分数、Four Four's、数式のパターン、クラスの定義、数式の生成、実行結果
- 2024/12/23 列 (Seq)
リストと列の違い、不変 (immutable) な列、列の生成、可変 (mutable) な列、ArraySeq、列のパターンマッチング、列の操作メソッド、列のソート、Ordering
- 2024/12/23 マップ (Map) とセット (Set)
マップとは?、不変 (immutable) なマップ、データの追加、データの削除、キーと値の取得、マップと列の変換、可変 (mutable) なマップ、マップの更新、セットとは?、不変 (immutable) なセット、データの追加、データの削除、集合演算、要素の取得、セットと列の変換、可変 (mutable) なセット、セットの更新、TreeMap と TreeSet、たらいまわし関数、メモ化による高速化、実行結果
- 2024/12/23 遅延評価
遅延評価とは?、たらいまわし関数の高速化、遅延ストリーム、遅延ストリームの構造、整数列の生成、フィボナッチ数列の生成、遅延ストリームの操作メソッド (1)、高階関数、遅延ストリームの操作メソッド (2)、高階関数 (2)、組 (tuple) を生成するストリーム、無限ストリームで組 (tuple) を生成する場合、素数列の生成、エラトステネスの篩、Scala の LazyList
- 2024/12/23 継続渡しスタイル
継続とは?、継続渡しスタイル (CPS) とは?、再帰呼び出しと継続渡しスタイル、二重再帰と継続渡しスタイル、CPS の便利な使い方、二分木の巡回を CPS で実装、二分木と遅延ストリーム、TailCalls、Appendix: 末尾再帰と繰り返し、末尾再帰をスタックオーバーフローせずに実行する
- 2024/12/23 自分型アノテーションと構造的部分型
自分型アノテーションとは?、型の指定、実装の切り替え、構造的部分型とは?、ダック・タイピング
- 2024/12/23 ヒープ
配列によるヒープの実装、ヒープの構築 (1)、ヒープの再構築、ヒープの構築 (2)、優先度つき待ち行列、実行例、PriorityQueue の使い方
●パズルの解法
- 2024/12/24 順列と組み合わせ
順列の生成、バックトラック法の実装、プログラムの作成、高階関数版の作成、リストの中から n 個の要素を選ぶ順列、順列をリストに格納する、要素の選択、順列をリストに格納する (2)、Scala の permuations、組み合わせの数、パスカルの三角形、組み合わせの生成、組み合わせをリストに格納する、組み合わせをリストに格納する (2)、Scala の combinations
- 2024/12/24 パズルの解法
問題1:小町算、問題2:覆面算、問題3:魔方陣、問題4:マスターマインド、解答1、別解、解答2、解答3、対称解の排除、解答4、プログラムの作成、何回で当たるか
- 2024/12/24 経路の探索
グラフ、隣接行列と隣接リスト、バックトラックによる探索、スタックによる深さ優先探索の実装、immutable なスタックを使う場合、幅優先探索、経路の管理、幅優先探索のプログラム、immutable なキューを使う場合、反復深化、反復深化のプログラム
- 2024/12/24 積木の移動
問題の説明、データ構造の定義、積木を動かす、深さ優先探索、幅優先探索、反復深化
- 2024/12/24 パズルの解法 (2)
問題1「騎士の周遊」、問題2「水差し問題」、問題3「Hoppers」、解答1、実行結果、解答2、実行結果、解答3、実行結果
- 2024/12/24 パズルの解法 (3)
8 パズルの説明、幅優先探索による解法、実行結果、双方向探索、最長手数の求め方、プログラムの作成、反復深化による解法、手数の遇奇性、プログラムの作成、下限値枝刈り法、下限値枝刈り法のプログラム
- 2024/12/24 整数の論理演算とビット操作
ビット演算子、組み合わせの生成、組み合わせに番号を付ける方法、組み合わせを番号に変換、番号を組み合わせに変換、ちょっと便利なビット操作、ビットが 1 の個数を求める、BitSet
- 2024/12/24 N Queens Problem
8 クイーンの解法、単純な生成検定法、実行結果、無駄を省く、実行結果 (2)、プログラムの改良、実行結果 (3)、ビット演算による高速化、実行結果 (4)
はじめに
Scala はスイス連邦工科大学 (EPFL) の Martin Odersky 教授によって設計されたプログラミング言語です。Scala はオブジェクト指向言語と関数型言語を統合した言語で、Java プラットフォーム (Java 仮想マシン) 上で動作します。Scala のオブジェクト指向はクラスベースで、継承は「単一継承」のみサポートしています。「多重継承」はサポートされていませんが、そのかわり Trait (トレイト) を使って Ruby のような Mix-in (ミックスイン) が可能です。また、Java と簡単に連携できるので、Java のライブラリ資産を有効に活用することができます。
Scala は強く型づけされた言語で、コンパイル時に静的な型チェックを行うことで、多くのエラーを検出することができます。Scala には ML (SML/NJ, OCaml) や Haskell などの関数型言語で有名な「型推論」という機能があるので、型宣言を省略してプログラムを簡潔に記述することができます。もちろん、パターンマッチング、クロージャ、カリー化など、関数型言語でよく使われている便利な機能がサポートされています。
M.Hiroi は Scala でプログラミングするのは初めてです。また、Java にも詳しいわけではないので、いきなり Scala に挑むのは無謀なことなのかもしれません。そこで、最初は M.Hiroi が知っている関数型言語の機能を中心に、簡単なプログラムを作りながら Scala を勉強していきたいと思っております。なにぶん初心者が作るプログラムなので、間違いや Scala の作法に反することがあるかと思います。何かお気づきの点がありましたらご指摘お願いいたします。たいしたことはできませんが、よろしければお付き合いくださいませ。
●インストール
Scala を実行するには Java の実行環境が必要です。M.Hiroi は OpenJDK 21 を使っています。Java のインストールは拙作のページ お気楽 Java プログラミング入門 - はじめに - Java のインストール をお読みください。
Scala は次のサイトからダウンロードできます。
2024 年 12 月時点で、最新バージョンは 2024 年 12 月にリリースされた Scala 3.6.2 ですが、本ページでは 2024 年 9 月にリリースされた Scala 3.3.4 (LTS) を使うことにします。上記サイトでも説明されているように、最近は Coursier というツールを使って Scala をインストールするのが推奨されていますが、ここでは GitHub で公開されている Scala binaries (scala3-3.3.4.tar.gz) を使用することにします。
たとえば、ディレクトリ ~/scala/ で scala3-3.3.4.tar.gz を展開すると、サブディレクトリ scala3-3.3.4 が生成されます。あとはサブディレクトリ bin にパスを通すだけです。次のコマンドを実行してください。
export PATH=~/scala/scala3-3.3.4/bin:$PATH
これでパスを通すことができます。上記のコマンドはファイル ~/.bashrc に追加しておくといいでしょう。
●プログラムの実行
Scala はプログラムをコンパイルするコマンド scalac と、コンパイルしたプログラムを実行するコマンド scala があります。これは Java のコマンド javac, java と同じ関係です。また、引数を指定せずにコマンド scala を実行すると、対話モード (REPL : Read-Eval-Print-Loop) で Scala を使用することができます。
$ scala
Welcome to Scala 3.3.4 (21.0.5, Java OpenJDK 64-Bit Server VM).
Type in expressions for evaluation. Or try :help.
scala>1 + 2 * 3
val res0: Int = 7
scala> :quit
$
REPL で Scala のプログラムを入力して簡単に実行することができます。終了する場合はコマンド :quit (または :q) か CTRL-D を入力してください。
次はお馴染みの Hello, world! を表示するプログラムを作ってみましょう。
リスト : hello.scala
object Hello {
def main(args: Array[String]): Unit = {
println("Hello, world!")
}
}
ファイル名は hello.scala とします。拡張子は scala です。Scala の場合、Java とは違ってファイル名は object の名前 Hello と同じにする必要はありません。hello.scala でも test.scala でもかまいません。
プログラムのコンパイルは scalac で行います。シェルで scalac hello.scala と入力すると、hello.scala がコンパイルされて Hello.class という class ファイルが作成されます。ファイル名が test.scala の場合でもコンパイル後に生成されるファイルは Hello.class になります。プログラムの実行は scala を使います。コマンドプロンプトで scala Hello と入力します。object Hello のメソッド main が呼び出されて Hello, world! が表示されます。
$ scalac hello.scala
$ scala Hello
Hello, world!
また、次のように対話モードでプログラムをロードして、実行することもできます。
scala> :load hello.scala
// defined object Hello
scala> Hello.main(Array())
Hello, world!
scala>
なお、hello.scala は scalac でコンパイルしなくても、スクリプト言語のように実行することもできます。
$ scala hello.scala
Hello, world!
●簡単なベンチマーク
Scala のプログラムは Java 仮想マシン上で動作するので、JIT (Just in Time) コンパイラなどの技術によりプログラムを高速に実行することができます。その実行速度ですが、たらいまわし関数を使って調べてみました。
リスト : たらいまわし関数 (Scala)
object Tarai {
def tak(x: Int, y: Int, z: Int): Int = {
if (x <= y) z
else tak(tak(x - 1, y, z), tak(y - 1, z, x), tak(z - 1, x, y))
}
def main(args: Array[String]): Unit = {
val start = System.currentTimeMillis
println(tak(22, 11, 0))
print(System.currentTimeMillis - start)
println("msec")
}
}
リスト : たらいまわし関数 (Java)
public class Tarai {
static int tak(int x, int y, int z) {
if(x <= y)
return z;
else
return tak(tak(x - 1, y, z), tak(y - 1, z, x), tak(z - 1, x, y));
}
public static void main(String[] args) {
long start = System.currentTimeMillis();
System.out.println(tak(22, 11, 0));
long end = System.currentTimeMillis();
System.out.println((end - start) + "ms");
}
}
それでは実行結果を示します。tak(22, 11, 0) を計算しました。
表 : tak(22, 11, 0) の結果
処理系 | 秒 |
Python (ver 3.10.12) | 62.23 |
Ruby (ver 3.0.2p107) | 25.59 |
Lua (ver 5.4.4) | 22.41 |
Gauche (ver 0.9.15) | 21.29 |
ocamlc (ver 4.13.1) | 9.46 |
SBCL (ver 2.1.11) | 4.90 |
Julia (ver 1.10.5) | 1.84 |
SBCL (最適化) | 1.50 |
Java (ver 21.0.5) | 1.22 |
GCC -O2 (ver 11.4.0) | 1.19 |
Scala (ver 3.3.4) | 1.11 |
ocamlopt (ver 4.13.1) | 1.05 |
- 実行環境 : Ubunts 22.04 (WSL2), Intel Core i5-6200U 2.30GHz
Scala は Julia や SBCL (Common Lisp) よりも速く、GCC, OCaml, Java に匹敵する速度をたたき出しています。Scala は大変優れたコンパイラ (処理系) だと思います。興味のある方はいろいろ試してみてください。
初版 2014 年 7 月 20 日
改訂 2024 年 12 月 16 日
Yet Another Scala Problems
参考文献, URL
- The Scala Programming Language, (本家)
- Scala プログラミング入門, (神戸大学, 田村直之先生)
- スケーラブルで関数型でオブジェクト指向なScala入門, (@IT, 中村修太さん)
- ひしだま's ホームページ - Scalaメモ, (ひしだまさん)
- Scala研修テキスト, (株式会社ドワンゴ)
権利・免責事項など
『お気楽 Scala プログラミング入門』の著作権は筆者「広井誠 (Makoto Hiroi) 」が保持します。無断使用や無断転載は禁止いたします。『お気楽 Scala プログラミング入門』で作成したプログラムはフリーソフトウェアとします。ご自由にお使いください。プログラムの改造や配布もご自由にどうぞ。その際は、出典を明記してくださるようお願いいたします。
ただし、これらのプログラムは無保証であり、使用したことにより生じた損害について、作者「広井誠 (Makoto Hiroi) 」は一切の責任を負いません。また、これらのプログラムを販売することで利益を得るといった商行為は禁止いたします。
Copyright (C) 2014-2024 Makoto Hiroi
All rights reserved.