第K章 プログラミング言語 Kotlin
Kotlin はジェットブレインズ (JetBrains) 社の Andrey Breslav, Dmitry Jemerov らにより開発されたマルチパラダイムのプログラミング言語である。登場したのは 2011 年である。

() 上で動作し、Java で書かれたプログラムと相互呼出しが可能である。また、JavaScript にコンパイルすることも可能になど現代的な特徴を取り入れ、“より良い” Java を目指してなっている。

設計されている。 Android のアプリケーションの開発言語として Google の推奨
言語にもなっている。
ここでは Java と異なる部分を中心に Kotlin を説明する。

K.1 Kotlin の実行
新しいプログラミング言語を学習するときの慣習により、最初に、画面に“Hello
World!”と表示するだけのプログラムを作成する。次のようなプログラムを好みのエディターで作成する。
ファイル Hello.kt
1 fun main() {2
println("hello, world!")
3 }これをというコマンドラインツールを用いてコンパイルする。

> kotlinc Hello.kt -include-runtime -d Hello.jar
コンパイルが成功すれば、同じディレクトリーに Hello.jar というファイルができている。これは Hello.kt に対する class ファイルと、必要な実行時ライブ
ラリーをひとまとめにしたものである。 実行するときは java コマンドの -jar
オプションを用いる。
> java -jar Hello.jar
また kotlinc コマンドを引数なしで実行すると、（対話的な処理系）が起動する。これは Java の jshell コマンドに対応する。対話的な処理系では、
プロンプト（通常、>>> ）のあとに式を入力すれば、その値を出力する。
Type :help for help, :quit for quit>>> 1 + 2
res0: kotlin.Int = 3
Kotlin の統合開発環境 (IDE) としては Eclipse などもあるが、 JetBrains 社が開発している IntelliJ IDEA が（当然ながら）有力である。 また、Java 用のビルドツールとして知られている Maven や Gradle なども Kotlin に対応している。

K.2 定義と宣言
パッケージとインポート

オブジェクト指向言語 第 K 章 p.1

パッケージ (package) やインポート (import) の書き方は Java とほとんど同じである。ただし、最後のセミコロンは省略できる。また、パッケージとソースを配置するディレクトリーを。

関数定義
Kotlin ではクラスの外で（トップレベルで）関数を定義することができる。逆に言うと、Java のスタティック (static) メソッドやスタティックフィールドのような概念はない。（ただし companion object というものが使われることがあるが、ここでは説明を割愛する。）
ファイル Twice.kt
1 fun twice(x: Int): Int {2
return x + x
3 }4
5 fun thrice(x: Int) = x + x + x
6
7 fun sayHello(): Unit {8
println("Hello!")
9 }10
11 fun sayGoodbye() {12
println("Goodbye!")
13 }14
15 fun main() {16
println(twice(2))
17println(thrice(2))
18
sayHello()
19
sayGoodbye()20 }関数 twice はもっとも基本的な関数定義のカタチを例示している。関数定義は
fun というキーワードから開始する。そのあとに関数名が続き、丸括弧の間「(」～「)」に仮引数をコンマで区切って宣言する。仮引数の宣言は、変数:型 というカタチをしている。さらに、閉じ丸括弧の後にコロン「」に続けて戻り値の型を書く。
ブレースの間「{」～「}」に文の並びを書く。なお、文末のセミコロン「;」は省略できる場合が多い。
関数 thrice で例示されているように、すぐに return する関数は 「」のあとにすぐに式を書くことも可能である。処理系が戻り値の型を推論できる場合
は、戻り値の型の宣言を省略できる。
その下の sayHello 関数のように戻り値を持たない場合は、戻り値の型はUnit とする。また、sayGoodbye 関数で示されているように、戻り値型がUnit 場合は宣言を省略することが可能である。
Kotlin のプログラムはという名前の関数から実行される。この main 関数

は、この例のように無引数であるか、または文字列 (String) の配列を引数に取る。

オブジェクト指向言語 第 K 章 p.2

print 関数と println 関数
関数 print は、引数を出力する。関数 println は引数を出力してから改行を
出力する。

変数宣言
変数もクラスの外に定義することができる。代入で値を変更しない変数はというキーワードで宣言する。（Java 言語で修飾子 final がついている変数に相当する。）一方、代入で値を変更する変数はというキーワードで宣言する。型を宣言する場合は、変数名のあとにコロン「:」に続けて型を書くが、初期値から型を推論できる場合はこの部分は省略できる。
ファイル VarTest.kt
1 val x: Int = 1
2 val y = 2
34 var v = 95
6 fun main() {7v -= 1
8
println("x = $x, y = $y, v = $v")
9 }

文字列リテラルと補間 (interpolation)
文字列リテラルは二重引用符「"」〜「"」で囲む。文字列の中の「$変数名」
や「${式}」はその変数や式の値に置き換えられる。

K.3 制御構造
条件判断
条件判断の if や if ～ else の書き方は C 言語や Java と大差はないが、Kotlin の場
合は if は“式”であり、値を持つことができる。
また when 式という、C や Java の switch 文に相当する構文もあるが、ここでは説明を割愛する。

繰り返し
ループの for 文は in というキーワードとともに、次のカタチで用いる。
for (変数 in 式) 文またはブロック
この in の次の式は配列などの“集まり”である。変数を集まりの各要素に割り当ててループ本体を繰り返す。
さらに for 文の in の次の式には range と呼ばれる 「」を使った式を書くこともできる。 for (i in 1..10) { … } なら 1 から 10 までの 10 回の繰り返しになる。

オブジェクト指向言語 第 K 章 p.3

また、while 文や do ～ while 文も、C 言語や Java と書き方は同じなので、説明は省く。（ただし、do ～ while 文の最後のセミコロン「;」は必要ない。）

例外処理
例外処理の try ～ catch も Java と書き方はほとんど同じだが、Kotlin の場合 try～ catch は文ではなく“式”である。また、例外の型は try 〜 catch (e:Exception) 〜 のように「:」のあとに記述する。

K.4 演算子と組み込み型
基本型
Kotlin の数値型は Int, Long, Float, Double のように、という点を除き Java と同じ名前を持っている。文字型は Char、真偽値型はBoolean である。Java であるようなプリミティブ型 (int, char, …) とラッパー
型 (Integer, Character, …) の使い分けは必要ない。

配列・リストKotlin の配列は総称型で、型パラメーターを持っている。Java と同様、型パラ
メーターはブラケット「」～「」のあいだに書く。例えば、文字列(String) を要素とする配列の型は Array<String> と表される。プログラムのエントリーポイントである main 関数が、コマンドライン引数を表す文字列の配列を引数として受け取るときは、その宣言は「fun main(args:) { … }」となる。
配列を作成するには可変個引数の関数を使う。

1 val ss: Array<String> = arrayOf("Takamatsu", "Kagawa", "配列の要素数は size というプロパティーで得ることができる。（ss の要素数
は ss.size） Java の配列の場合の length と異なるので注意する。
Kotlin の基本的なコレクション (collection) 型としては配列 Array<T> のほかに
リスト List<T>、 セット Set<T>、マップ Map<K, V> などがある。Array は
アクセスの効率は良いが、要素数を一度決めたら変更することができないのに対し、 List はアクセスの効率は犠牲になるが、要素数を容易に変更することができる。リストを作成するには可変個引数の関数を用いる。

1 val fruits: List<String> = listOf("banana", "orange", "pナル (null) 許容型
Kotlin と Java の大きな違いの一つは、通常の Kotlin の型はナル (null) を許容しないというところである。例えば、String 型の変数に null を代入することは型エラーになる。
1 var s: String = null// コンパイル時にエラー

オブジェクト指向言語 第 K 章 p.4

型のあとに「」をつけると null を許容する型になる。
// これは OK

1 var t: String? = null

このように null を許容する型の式に対してドット「.」演算子でプロパティー
やメソッドをアクセスすることは許されていない。
1 println(t.length)
そこで「// コンパイル時にエラー」演算子を用いると null を許容する型の式のプロパティーやメソ

ッドにアクセスできて、レシーバー（「.」や「?.」の左オペランド）が nullのときは結果も null になる。また「」演算子は左オペランドが null でな

いときはその値を、null のときは、右オペランドの値を返す。
1 println(t?.length)// これは OK --- t が null なら n
2 println(t?.length ?: 0) // t が null なら 0

コメント
Kotlin のコメントは Java と同じで、「

」から「

」までと「

」から行

末まで、である。

タプル
Pair, Triple はそれぞれ 2 つ組、3 つ組を表す総称データ型である。
ファイル Quadratic.kt
1 import kotlin.math.*2
3 fun quadratic(a: Double, b: Double, c: Double):4
Pair<Double, Double> {5val d = b * b - 4 * a * c
6val sq = sqrt(d)7return Pair((-b + sq) / (2 * a), (-b - sq) / (2 * a)8 }関数 quadratic は二次方程式 ax + bx + c = 0 の 2 解
22−b ± √ b

2a

− 4ac

を

Pair として返している。
Pair や Triple からは destructuring declaration （分割宣言(?)）という記法
で、構成要素を取り出すことができる。キーワードの val や var のあとに、丸
括弧で囲った変数のコンマ区切りの並びを書く。
ファイル Quadratic.kt
10 fun main() {11val a = 1.0; val b = -1.0; val c = -1.0
12val (x1, x2) = quadratic(a, b, c)
13
println("方程式の解は、$x1、$x2 です。")
14 }オブジェクト指向言語 第 K 章 p.5

この例では、Pair の第 1 成分が x1 に、Pair の第 2 成分が x2 に取り出される。
Kotlin の標準ライブラリーには 4 つ組以上のタプルは用意されていないが、データクラス (data class) という宣言で、このような分割宣言を利用できるデータ型を定義することができる。データクラスの説明はここでは割愛する。
問 K.4.1 引数として Double の配列 arr を引数として受取り、配列中の要素の最大値と最小値を組 (Pair) として返す Kotlin の関数 fun maxMin(arr:Array<Double>): Pair<Double, Double> を定義せよ。（配列の要素数
は 1 以上と仮定して良い。）
また main 関数は次のコードを利用せよ。
1 fun main() {2
val a1 = arrayOf(9, 8, 7, 6)
3
val a2 = arrayOf(1, 4, 3, 2)
4
val a3 = arrayOf(-4, -3, -2, -1)
56
val (x1, n1) = maxMin(a1)7println("a1 の最大値は $x1、最小値は $n1")
8val (x2, n2) = maxMin(a2)9println("a2 の最大値は $x2、最小値は $n2")
10val (x3, n3) = maxMin(a3)11println("a3 の最大値は $x3、最小値は $n3")
12 }K.5 クラスとオブジェクト
クラス定義
クラスはキーワードを使って定義する。Kotlin のクラスはデフォルトでは final である。つまりサブクラスを定義することができない。サブクラスを定義する場合は class の前にというキーワードをつけなければいけない。

ファイル Point.kt
1 open class Point(var x: Double, var y: Double) {2
open fun show() {3
print("($x, $y)")4}
5
fun move(dx: Double, dy: Double) {6x += dx; y += dy
7}8
fun moveAndShow(dx: Double, dy: Double) {9move(dx, dy)
10show()
11}
12 }キーワード class のあとにクラス名が続く。そのあとに丸括弧「(」～「)」の中に囲んで、コンストラクターの仮引数の宣言を続ける。このコンストラクタ
ーはプライマリー（つまり第一の）コンストラクターと呼ばれる。 引数の型やオブジェクト指向言語 第 K 章 p.6

数が異なる、第二、第三のコンストラクターを定義することも可能だが、ここではその説明を割愛する。
プライマリーコンストラクターの引数で、そのままプロパティー（property —Kotlin のインスタンス変数）の初期値となるものは、再代入可能なプロパティーの場合は、キーワード var を、再代入不可能なプロパティーには、キーワード
val を変数宣言の前につける。こうしておけば、改めてクラス定義の本体にプロパティーの宣言を書く必要はない。
ブレース「{」～「}」の間がクラス定義の本体で、メソッドや、プライマリー
コンストラクターで定義していないプロパティーの宣言などを書く。
Kotlin のメソッドはデフォルトではオーバーライド (override) 不可である。サブクラスでオーバーライドできるようにするには、 fun の前にというキーワードをつけなければならない。また、サブクラスでオーバーライドするとき
は、 fun の前にというキーワードをつける。

ファイル Point.kt
14 class ColorPoint(x: Double, y: Double, var color: String
15
Point(x, y) {16
override fun show() {17
print("<font color='$color'>($x, $y)</font>")
18
}
19 }
20
21 class DeepPoint(x: Double, y: Double, var depth: Int):
22
Point(x, y) {23
override fun show() {24
if (depth <= 0) {25
print("$x, $y")26
} else {27
print("(".repeat(depth) + "$x, $y"28+ ")".repeat(depth))
29
}
30
}
31 }

サブクラスを定義するときは、 プライマリーコンストラクターの後にコロン「」に続けて スーパークラスのコンストラクターの式を書く。 ColorPoint とDeepPoint のコンストラクターでは、x と y は定義されるクラスのプロパティ
ーではない （スーパークラスの Point で既に定義されている）ので var や
val がついていないことに注意する。
ファイル PointTest.kt
1 fun main() {2val points = arrayOf(Point(1.1, 2.5),
3
ColorPoint(2.1, 3.9, "red"),
4
DeepPoint(1.9, 0.25, 5))5for (p in points) {6
p.moveAndShow(1.5, -0.5)
7
println()8}9 }オブジェクト指向言語 第 K 章 p.7

関数 main を上のように定義するとき、このプログラムは(2.6, 2.0)と出力する。コンストラクターを呼び出すときに new というキーワードはつけないことにも注意する。
Kotlin のクラスのプロパティーには読み・書きにそれぞれゲッター (getter)・セッター (setter) というメソッドを関連づけることができる。その文法の詳細の説
明は割愛する。

インタフェース
インタフェースを定義するときは interface というキーワードを用いる。そのあとにインタフェース名を続け、ブレース「{」～「}」の間に、プロパティ
ーやメソッドの宣言を書く。
ファイル Movable.kt
1 interface Movable {2
fun tick()3
fun getLoc(): Point
4 }あるクラスがインタフェースを実装 (implements) するときは、スーパークラスと同じようにコロン「:」のあとにインタフェース名を書く。複数のインタフェースを実装するときは、インタフェース名をコンマ「,」で区切って並べて書く。

オブジェクト
匿名クラスのオブジェクトを生成するときは、というキーワードを用いる。それに続くブレース「{」～「}」の間に、プロパティーやメソッドの定義を書く。スーパークラスやインタフェースを指定するときは、object というキーワードに続けてコロン「:」のあとにスーパークラスのコンストラクターの呼び出し式、またはインタフェース名（のコンマ「,」区切りの並び）を書く。
ファイル Movable.kt
6 fun main() {7val m = object: Movable {8
var x = 0.0
9var y = 0.010override fun tick() {11x += 24; y += 15
12
if (x > 100) x -= 100
13
if (y > 100) y -= 100
14
if (x < 0)x += 10015
if (y < 0)y += 10016}
17
override fun getLoc(): Point = Point(x, y)18}19
for (i in 1..10) {20
m.tick()21
m.getLoc().show()22}

オブジェクト指向言語 第 K 章 p.8

23 }インタフェースのメソッドを実装するときは override キーワードが必要となる。

拡張関数
Kotlin では既存のクラスにメソッドを追加するかのように見せかけることができ
る。これを

(

) と呼ぶ。

拡張関数は fun クラス名.メソッド名(…) で定義を開始する。関数内部でレシーバー（ドット「.」の左オペランド）のメソッドやプロパティーは、その名前だけでアクセスすることができる。また、レシーバーそのものはキーワード
で参照することができる。
ファイル ExtensionTest.kt
1 import kotlin.math.*2
3 fun Point.rotate(theta: Double) {4
val x0 = x
5val y0 = y6x = x0 * cos(theta) - y0 * sin(theta)7y = x0 * sin(theta) + y0 * cos(theta)
8 }次の例では上で定義した拡張関数の rotate を本来のメソッド（show や moveなど）と同じ文法で呼び出していることがわかる。
ファイル ExtensionTest.kt
10 fun main() {11val p = Point(1.0, 0.0)
12
p.rotate(PI / 6)
13
p.show()
14 }

ただし、拡張関数はクラスを拡張したように“見せかけている”だけなので、本当にクラスを拡張しているのではない。拡張関数は動的束縛ではなく、静的に（コンパイル時に）推論される型から選択される。例えば次の例では、main
で、変数 p の型が Point と宣言されているので、p.bar() の呼び出しにはPoint.bar() のほうが選択されて、ファイル ExtensionTest2.kt
1 fun Point.bar() {2
print("Point class: ")3
show()
4
println()
5 }6
7 fun ColorPoint.bar() {8
print("ColorPoint class:")9
show()
10
println()

オブジェクト指向言語 第 K 章 p.9

11 }
12
13 fun main() {14
val p: Point = ColorPoint(1.0, 0.0, "black")
15
p.bar()
16 }と出力する。

K.6 関数リテラルと高階関数
関数リテラルKotlin の関数リテラルは、キーワード fun を使う書き方（ース「{」～「}」・矢印「->」を使う書き方（）と、ブレ）がある。他の言語

では匿名関数とラムダ式は同じものを指すことが多いが、 Kotlin では使い分けている。
匿名関数:「fun ( 仮引数宣言の並び ): 型 { 文の並び } 」または
「fun ( 仮引数宣言の並び ): 型 = 式」
ラムダ式:「{ 仮引数宣言の並び -> 文の並び }」ここで仮引数宣言の並びはコンマ「,」区切りである。また、関数の型は「(型, 型, …, 型 ) -> 型」のように「->」を使って表す。矢印の左辺の丸括
弧の中が引数の型、右辺が戻り値の型である。
ラムダ式では return を使わなくても、文の並びの最後の文の式の値が戻り値になる。また、ラムダ式に仮引数がないときは「->」も省略できるので、ブレース「{」～「}」のなかに文の並びだけを書くことになる。

高階関数
高階関数 (higher-order function) は関数を引数としたり、戻り値としたりする関数である。Kotlin の標準ライブラリーには、いくつかの便利な高階関数が用意されている。例えば

メソッドはリストや配列などのコレクションの要素に引数の関数を一斉に適用し、その戻り値のコレクションを返す。またメ

ソッドはコレクションの要素のなかで、引数の関数の値を真にするような要素だけのコレクションを返す。
ファイル LambdaTest.kt
1 fun main() {2
val xs: List<Int> = listOf(2, 3, 5, 8)
3
println(xs.map { x -> x * x })4
println(xs.filter { x -> x % 2 != 0 })5 }Kotlin では、関数・メソッドの最後の引数がラムダ式の場合、という約束事がある。特に、ラムダ式が唯一の引数であるときは丸括弧自体を省略して良い。この約束事のおかげで、まるで if や
while などの制御構造と同じような外見で、関数適用を書くことができる。

オブジェクト指向言語 第 K 章 p.10

結局、上のプログラムは次のように出力する

K.7 プログラム例
ここでは Java のライブラリーを使うプログラムを Kotlin で記述した例を紹介する。最初は AWT と Swing を使うプログラムの例である。
ファイル SwingTest.kt
1 import java.awt.*
2 import javax.swing.*
3
4 fun factorial(n: Long): Long5
= if (n == 0L) 1L else n * factorial(n - 1L)
6
7 fun main() {8
SwingUtilities.invokeLater {9val panel = JPanel()10
panel.setPreferredSize(Dimension(300, 50))
11val input = JTextField("0", 8)12val output = JLabel("1")
13
input.addActionListener { _ ->14
val n = input.getText().toLong()
15
output.setText("" + factorial(n))
16}17panel.add(input)
18
panel.add(JLabel(" の階乗は "))19panel.add(output)
20
panel.add(JLabel(" です"))21
22
val frame = JFrame("Hello")
23
frame.add(panel)
24
frame.pack()
25
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CL
26
frame.setVisible(true)
27
}
28 }

次の例も AWT と Swing を使っているが、object を使っている例である。
ファイル Gradation.kt
1 import java.awt.*
2 import javax.swing.*
3
4 fun main() {5
SwingUtilities.invokeLater {6
val panel = object: JPanel() {7override fun paintComponent(g: Graphics) {8super.paintComponent(g)9val scale = 4;
10
for (i in 0..63) {11
g.setColor(Color(i * 4, 0, 255 - i *12g.fillRect(i * scale, 0, scale, 40)
13
}
14
}

オブジェクト指向言語 第 K 章 p.11

15
16
17
18
19
20
21
22
23
24 }

}
panel.setPreferredSize(Dimension(256, 40))}

val frame = JFrame("Gradation")frame.add(panel)
frame.pack()
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CL
frame.setVisible(true)

最後は Servlet の例である。
ファイル HelloKotlin.kt
1 import jakarta.servlet.annotation.WebServlet
2 import jakarta.servlet.http.HttpServlet
3 import jakarta.servlet.http.HttpServletRequest
4 import jakarta.servlet.http.HttpServletResponse
5
6 @WebServlet("/HelloKotlin")
7 class HelloKotlin : HttpServlet() {8protected override fun doGet(request: HttpServletReque9
response: HttpServletResp
10response?.setContentType("text/html; charset=UTF-8")
11
response?.getWriter().use { out ->12
out?.println("""13<!Doctype HTML>14<html>
15<head><title>Hello Kotlin</title></head>16<body>
17<h1>Hello Kotlin</h1>
18<p><span style="color: blue;">Hello</span> Kot
19</body>20</html>
21
""")
22
}
23
}
24 }

K.8 シーケンス
シーケンス
シーケンス (Sequence) は配列やリストと同様にコレクションだが、遅延評価
される（つまり、必要になるまで評価されない）という点が異なる。このため
無限個の要素を持つシーケンスを定義することもできる。シーケンスを生成する関数としては generateSequence, sequence などがある。前者は初期値 aと“漸化式” f を受け取り、無限列 a, f (a), f (f (a)), f (f (f (a))), … を返す。後者は無引数のラムダ式を受け取り、ラムダ式の中の文を実行して関数に渡される値を順に生成する。いったん yield 関数が呼び出されると、ラムダ式の中の文の実行は中断されるが、シーケンスの次の要素が必要になったとき

オブジェクト指向言語 第 K 章 p.12

に、 yield の呼び出しの、やはり、次に yield に渡される値を返す。ラムダ式の実行が終了すると、シーケンスも終了する。
もちろん無限列はそのまま出力しようとすると、プログラムが止まらなくなってしまう。次のプログラムでは take(n) メソッドで先頭の n 個の要素からなる有限列を取り出して、 toList() メソッドでリストに変換して出力している。
ファイル SequenceTest.kt
1 fun main() {2
val nums = generateSequence(1) { x -> x + 3 }3println(nums.take(10).toList())
4
val fibs = sequence {5
var a = 1; var b = 1
6while (true) {7yield(a)8val c = a9a = b; b += c
10
}
11
}
12
println(fibs.take(10).toList())
13 }このプログラムは次のように出力する。

次のプログラムは、シーケンスによるエラトステネスの篩のアルゴリズムの実装である。ここで elementAt(n) は n 番目の要素を取り出すメソッド、
drop(n) は先頭の n 個の要素を除いた残りを返すメソッドである。
ファイル Primes.kt
1 fun main() {2val primes = sequence {3
var nums = generateSequence(2) { x -> x + 1 }4while (true) {5
val a = nums.elementAt(0)6yield(a)7nums = nums.drop(1).filter { b -> b % a != 0
8
}
9
}
10
println(primes.take(20).toList())
11 }このプログラムは次のように出力する[2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59

K.9 練習問題
問 K.9.1 a, b, c が整数で a, b が正または 0 かつ、c が 0 でないとき、不定方程式:
ax + by = c

オブジェクト指向言語 第 K 章 p.13

の整数解 (x, y) は、次のような手順で再帰的に求める（または解が存在しない
ことを示す） ことができる。
（注: この手順は、解を 1 組だけ求める。一般に解が存在する場合は、解は無数に存在するが、 1 組の解 (x, y) が求まれば他の解は容易に求めることができる。例えば、 (x ± b, y ∓ a), (x ± 2b, y ∓ 2a), … なども解であることがわかる。）（注: 実は a, b は負でも全然構わないのだが、余りの演算「%」の値の正負を気にしなくても良いように、ここでは正に限ることにする。また c が 0 だと、
x = 0, y = 0という当たり前すぎる解が存在する。）

b が 0 のとき、
c % a が 0 ならば、(c / a, 0) が解である（「/」は整数としての割算）。
c % a が 0 でないならば、解は存在しない。
b > 0 のとき、a % b を r とおき、新しい方程式:′′bx + ry = cの整数解を（再帰的に）求める。
この方程式が解を持たなければ、元の方程式も解を持たない。
この方程式が解 (x', y')を持てば、 q を a / b とおくと、(y', x' - q * y') が元の方程式の解である（「/」は整数としての割算）。
説明: a = bq + r だから、′′bx + ry = c
⇔
⇔

′

′

bx + (a − bq)y = c′′′

ay + b(x − qy ) = c

この手順を用いて、正または 0 の整数 a, b と、 0 でない整数 c を受け取り、方
程式:
ax + by = c

が
解 x, y を持つときは、その解を組 Pair(x, y) として返し、解を持たないときは、組 Pair(0, 0) を返す、
関数 fun bezout(a: Int, b: Int, c: Int): Pair<Int, Int> を定義せよ。
また main 関数は次のコードを用いよ。
1 fun main() {2
val arr = arrayOf(Pair(5, 7), Pair(5, 17), Pair(7,3for ((a, b) in arr) {オブジェクト指向言語 第 K 章 p.14

4
5
6
7
8
9
10
11 }

}

val (x, y) = bezout(a, b, 1)
if (x != 0 || y != 0) {println("$a x * $b y = 1 の解は x = $x, y =} else {println("$a x * $b y = 1 の解はなし")}

問 K.9.2 シーケンス primes（または generateSequence(2) { x -> x +1 }）を利用して、正の整数を受け取って素因数分解し、結果を昇順のシーケンスとして返す関数 fun factorization(num: Int): Sequence<Int>を定義せよ。例えば、factorization(360).toList() は [2, 2, 2, 3,
3, 5] であり、 factorization(1024).toList() は [2, 2, 2, 2, 2,
2, 2, 2, 2, 2] である。
factorization を呼び出す側は次のコードを用いよ。
1 fun main() {2while (true) {3
print("正の整数を入力してください: ")4val n = try {5
readLine()?.toInt()?:06} catch (ex: Exception) { 0 }7
if (n <= 0) {8
println("終了します")
9
break
10
}
11
val result = factorization(n).toList()
12
println("$n の素因数分解の結果は $result です。")
13
}
14 }

オブジェクト指向言語 第 K 章 p.15