# 言語

この部は、v0 処理系（`bin/sake`）が実装している Sake という言語そのものを、10 章と付録 1 つで述べます。読み手として、Ruby を知っている人と、Ruby を知っている言語モデルを想定しています。構文は Ruby のものなので、この部が説明するのは「Ruby と同じ字面に Sake が与える意味」と「Ruby には無い規則」です。

## 一つの考え

Sake のプログラムは Ruby の構文で書きますが、`name.upcase` とは書かず、`String.upcase(name)` と書きます。型を名乗るのは**操作**だけで、変数・引数・返り値・フィールドには何も書きません。

```ruby
words = String.split("the cat and the hat", " ")
counts = Hash.new(0)
Array.each(words) { |w| counts[w] += 1 }
p(Hash.to_a(counts).Array.sort_by { |w, n| -n }.first(2))   # [["the", 2], ["cat", 1]]
```

この一つの決まりから、言語の性質がほぼすべて出てきます。

- **多くの呼び出しは 1 行で呼び出し先が分かる。** `Array.each(words)` はどの `each` か、宣言を探さなくても読めます。連鎖 `Array.sort_by(xs) { }.first(3)` の `.first` は、同じ行で最後に名乗った Array の操作です。
- **呼び出し先は実行前に決まる。** `String.upcase(s)` は 1 つの関数を名指しします。module の mixin 関数 `M.f(x)`、型の列挙 `(A|B).f(x)`、演算子 `a + b` は第 1 引数の型で 1 つを選びますが、候補の集合（`M` を include する型、列挙した型、演算子の表）は実行前に確定していて、集合の外の型は実行前に報告されます。レシーバで動的に探す仕組み（`method_missing`、リフレクション）は無いので、名前の誤り（`String.upcse`）や引数の数の誤りも、プログラム全体について実行前に報告されます。
- **型は書かずに推論する。** 検査器はプログラム全体の型を推論し、操作に合わない値（`"" + 1`、検査していない nil）を実行前に報告します。どこまで止めるかは `--strict` のレベル 0〜4 で選びます。
- **実行時の検査は残る。** 値は型タグを持ち、すべての操作が引数を検査するので、実行前の検査が見逃したものもその操作の行で止まります。

Ruby と字面が同じでも意味が違うものがいくつかあります。`[a, b]` は Tuple、`{x: 1}` は Record で、Array と Hash は `Any[...]`、`Hash.of(...)` と書きます。`class` の中の `@x` は「第 1 引数のフィールド x」で、インスタンスの状態ではありません。`class B < A` は A の定義を B に写す略記で、継承ではありません。この部の各章が、そうした違いを一つずつ述べます。

## 章の案内

| 章 | 内容 |
|---|---|
| [概要と実行](01-overview.md) | 4 つの原則、コマンドと終了コード、`--strict` のレベル 0〜4 と各項目（`type`、`nil`、`mixed`、`index-nil`、`exhaustive`、`rescue`、`unrescued`）、静的・実行時エラーの形式。 |
| [プログラムの構造と名前解決](02-program.md) | ファイルと `require`、型付きの呼び出し `T.f(x)`、連鎖 `T.f(x).g` と `_`、値へのメソッド呼び出しが無いこと、型を付けない呼び出し（自分の関数、`puts`、`p`）、`include`、`module_function` とディスパッチ、型の列挙 `(A\|B).f(x)`、引数の数とブロック。 |
| [値と型](03-values.md) | 値の表示、Tuple・Record・Array の区別、Hash と Set、nil と `nil \| T` の絞り込み、Ruby の他の型（Symbol、Range、Regexp、Time、Rational、Complex）。 |
| [関数とブロック](04-functions.md) | 注釈の無い多相な関数、省略できる引数とキーワード、`yield` で渡すブロック、`once`。 |
| [演算子と添字](05-operators.md) | `a + b` は `Arithmetic.+(a, b)` の略記で、左のオペランドの型に解決されること、`Arithmetic`・`Comparable`・`Bitwise`・`Indexable` を include して自分の型に演算子を与えること、`a[i]` と `a[i] = v`。 |
| [制御構造とパターン](06-control.md) | `if`・`while`・`case`/`in`、`x in T` による絞り込み、`case` の網羅性の検査。 |
| [クラス](07-classes.md) | `class` と `attr_*` による型の宣言（`Struct.new` はその略記）、`@x` の意味、`initialize`、`class B < A`、構築場所ごとに 1 つの型。 |
| [例外とエラー](08-exceptions.md) | `raise`・`rescue`・`ensure`・`retry`、例外型の宣言、関数から漏れる例外の推論、静的エラーと実行時エラーの種類。 |
| [組み込み操作](09-builtins.md) | 約 550 の組み込み操作の概観（名前は Ruby の core と同じ）と型付き Array `T[...]`。各操作の正確な署名と例は[組み込みリファレンス](part-reference.md)に。 |
| [ライブラリ（sakelib）](10-library.md) | 標準添付ライブラリと gem の移植、minitest、テストの書き方。 |
| 付録 [Ruby との違いと未対応のもの](a1-ruby.md) | Ruby の書き方から Sake の書き方への対応表、未対応の構文と機能、設計の資料。 |

## 読み方

- **Ruby を知っていて書き始めるなら**、[概要と実行](01-overview.md)、[プログラムの構造と名前解決](02-program.md)、[値と型](03-values.md)、[演算子と添字](05-operators.md)の順に読み、付録の対応表を手元に置くと、ほとんどの静的エラーの意味が分かります。クラスを宣言するときに[クラス](07-classes.md)を読んでください。
- **言語モデルに書かせるなら**、この部の規則を 4 ページに圧縮した [cheatsheet.md](https://github.com/ko1/sake-lang/blob/main/docs/cheatsheet.md)（約 1 万トークン）を渡します。順を追った入門は [tutorial.md](https://github.com/ko1/sake-lang/blob/main/docs/tutorial.md) です。
- **試すなら**、[playground](https://ko1.github.io/sake-lang/playground/)がブラウザで動きます。補完、入力中の診断、ホバーで推論された型が見られます。
- **約束。** 例の中の `# 値` は `bin/sake` の実際の出力です。「静的エラー」は実行前に報告され何も走らないもの、「実行時エラー」はその操作で止まるものを指します。「レベル n」は `--strict=n` のことです。

# 概要と実行

Sake（/seɪk/）は、型を書く場所を変えてみるための実験的な言語です。構文は Ruby のまま、型は**操作**に書き、変数・引数・返り値・フィールドには書きません。

```ruby
name = "sake"
puts(String.upcase(name))      # => SAKE
```

Ruby の書き方 `name.upcase` は静的エラーです。hint が上の形を示します。

```ruby error
name = "sake"
puts(name.upcase)              # !> method call on a value `name.upcase` is not allowed
```

この本は、v0 インタプリタ（`bin/sake`）が実装している言語の参照マニュアルです。入門には [tutorial.md](https://github.com/ko1/sake-lang/blob/main/docs/tutorial.md) を、短い要約には [cheatsheet.md](https://github.com/ko1/sake-lang/blob/main/docs/cheatsheet.md) を参照してください。cheatsheet は約 1 万トークンで、AI に渡す用です。設計の経緯は `DESIGN.md` にあります。

## 原則

Sake の性質は、次の 4 つの原則からほぼすべて出てきます。この部の各章は、どれもこの 4 つの帰結です。

1. **Ruby の構文。** Sake のプログラムは Prism が構文解析できる Ruby のプログラムです。Ruby の構文の部分集合を受け付け、いくつかの構文には別の意味を与えます。
2. **型は操作に書き、束縛には書かない。** 操作は `Type.op(subject, args...)` と、型を付けて呼びます。変数・引数・返り値・フィールドに型注釈はありません。
3. **呼び出し先は実行前に決まる。** `String.upcase(s)` は 1 つの関数を名指しします。module の mixin 関数 `M.f(x)`、型の列挙 `(A|B).f(x)`、演算子 `a + b` は第 1 引数の型で 1 つを選びますが、候補の集合は実行前に確定しています。候補とは、`M` を include する型、列挙した型、演算子の表のことです。集合の外の型は実行前に報告されます。レシーバで動的に探す仕組み（`method_missing`、リフレクション）は無いので、名前の誤り（`String.upcse`）や引数の数の誤りも、プログラム全体について実行前に報告されます。
4. **値は型タグを持ち、すべての操作がそれを検査する。** 型の誤りは、その値を受け取った操作の行で報告されます。この検査は常に有効です。

原則 4 の検査は、実行前の検査が見逃したものを捕まえます。次の例では、無いキーの `h["b"]` が nil を返し、`String.upcase` がその行で止まります。

```ruby error
h = Hash.of("a" => "x")
puts(String.upcase(h["b"]))    # !> TypeError: String.upcase: argument 1 must be String, got nil
```

## 実行

`bin/sake` はプログラムをまず検査し、問題が無ければ実行します。オプションで、検査だけにするか、どこまで厳しく検査するかを選びます。

```
bin/sake FILE.sake              # 検査してから実行
bin/sake -c FILE.sake           # 検査のみ
bin/sake --strict FILE.sake     # より厳しく検査（レベル 2）してから実行
bin/sake --strict=3 FILE.sake   # レベル 0〜4、または項目名: --strict=type,nil
bin/sake --types FILE.sake      # 実験的: 推論した型を表示する
bin/sake --dump=ast FILE.sake   # 解決済みのプログラム（SakeAST）を表示する
```

| 終了コード | 意味 |
|---|---|
| 0 | 成功 |
| 1 | 実行時エラー |
| 2 | 実行前に問題が見つかった（何も実行していない） |

インタプリタは Ruby で書かれ、Ruby 4.0 を必要とします（4.0.2 と Prism 1.9.0 で試験）。他の依存はありません。

## 厳格さ（`--strict`）

`--strict` は、実行前にプログラムを止める問題の種類を選びます。検査器はプログラム全体の型を推論し、見つけた問題を**項目**（`type`、`nil` など）に分けて報告します。レベルは、どの項目でプログラムを止めるかの組み合わせです。報告されなかったものは、実行時に各操作が検査します。

| レベル | オプション | 加わる項目 | 止めるもの |
|---|---|---|---|
| 0 | `--strict=0` | （無し） | 常に検査されるもの |
| 1 | 既定 | `type`, `rescue` | 型の不一致、前の節が既に捕まえる `rescue` |
| 2 | `--strict` | `nil`, `mixed` | 検査していない nil、フィールドに出会った型 |
| 3 | `--strict=3` | `index-nil`, `exhaustive` | 添字の「外れ」の nil、網羅していない `case` |
| 4 | `--strict=4` | `unrescued` | トップレベルまで届く `raise` |

各レベルは、下のレベルの項目をすべて含みます。`unused-rescue` だけはどのレベルにも入らず、選ばない限り警告です（`--strict=2,unused-rescue`）。

### 常に検査されるもの（レベル 0）

次の問題はレベルに関係なく、実行前にプログラムを止めます: 構文、名前、引数の数、ブロック、値へのメソッド呼び出し、禁止構文、`T[...]` のリテラルの型。

### `type`（レベル 1）

nil 以外の、操作に合わない型の値です。`"" + 1` のように型が確定している場合も、1 か `""` を返す `pick()` の `pick() + 1` のように、合わない型を取りうる場合も報告します。

```ruby error
def half(n) = n / 2
puts(half("ten"))              # !> the operands are (String, Integer), which the left operand's type does not support [type]
```

報告は `half` の中の `n / 2` の行に出ます。hint の `reached by the call at line 2` が、そこに至った呼び出しを示します。

### `rescue`（レベル 1）

同じ `begin` の前の節が既に捕まえるので、決して届かない `rescue` 節です。例は[例外](08-exceptions.md)の「モジュールでまとめる」にあります。

### `unused-rescue`（警告）

begin 本体が決して投げない例外の `rescue` です。対象は、プログラムが宣言した例外型と `RuntimeError` です。`KeyError` や `ZeroDivisionError` のような組み込みの種類は、普通の操作からも上がりうるので、常に起こりうるものとして扱われ、報告されません。

警告で、プログラムは走ります。防御的な `rescue` は普通に書くものですし、その例外を投げるものがあるかはプログラム全体で決まります。ライブラリの中の、一部のアプリしか投げない例外の `rescue` が、他のアプリを全部止めてしまうことになります。エラーにするには項目を選びます: `--strict=2,unused-rescue`。

```ruby
class ParseError < StandardError
end
begin
  p(10 / 2)                    # => 5
rescue ParseError              # warning: the begin body never raises ParseError [unused-rescue]
  p(0)
end
```

### `nil`（レベル 2）

nil かもしれない値を、検査なしに使うことです。レベル 1 では実行時の `TypeError` になるものが、レベル 2 では実行前に報告されます。

```ruby error
words = String.split("a b", " ")
w = Array.find(words) { |x| x == "c" }
puts(String.upcase(w))         # !> argument 1 may be nil (nil | String) [nil]
```

ただし、「外れ」の nil は除きます。外れとは、添字 `x[k]`、`Array.dig`、`Hash.dig`、`MatchData.begin`/`end`、および空の容器への次の操作が返す nil です: `Array.first`, `last`, `pop`, `shift`, `min`, `max`, `minmax`, `at`, `slice`, `sample`, `delete_at`, `Set.first`, `min`, `max`, `min_by`, `max_by`。これらはレベル 3 の `index-nil` が対象にします。nil の絞り込み方は[値と型](03-values.md)にあります。

### `mixed`（レベル 2。レベル 1 では警告）

`mixed` は `type` の報告の一種です。合わない型のすべてが、合う型と一緒に、あるクラスの 1 つのフィールドに現れるときに付きます。フィールドに入った容器の要素も同じです。

検査器はフィールドに構築場所ごとの型を与えます（[クラス](07-classes.md)）。1 つの場所で作ったインスタンスを別々の値に使うと、型がそのフィールドで出会います。次の例では、`make()` が作る Heap を Integer 用と String 用に使っています。

```ruby error
class Heap
  attr_accessor items
  def initialize(h)
    @items = Any[]
  end
  def push(h, x) = Array.push(@items, x)
  def top(h) = Array.first(@items)
end
def make() = Heap.new(nil)
ints = make()
Heap.push(ints, 1)
strs = make()
Heap.push(strs, "a")
p(Heap.top(ints) + 1)          # !> the operands may be (nil, Integer), (String, Integer), which the left operand's type does not support [mixed]
```

このような報告は、誤りではなく出会いである可能性が高いので、レベル 2 からプログラムを止め、レベル 1 では警告として印字します。上の例はレベル 1 では警告を出した後に走り、`2` を印字します。

この見分けの代償として、同じ場所で本当に誤った型がフィールドに入った場合も `mixed` になります。例えば `Config.new("h", port)` の `port` が 80 のことも `"eighty"` のこともあるときです。そのような値は格納する場所、`initialize` で検査してください（`@port => Integer`）。

### `index-nil`（レベル 3）

「外れ」の nil（上記）を検査なしに使うことです。次のプログラムはレベル 2 までは走り、`2` を印字します。

```ruby
xs = Any[1, 2, 3]
x = xs[0]
p(x + 1)                       # => 2
```

レベル 3 では実行前に止まります。

```
$ bin/sake --strict=3 index.sake
index.sake:3:3: error: Arithmetic.+: the operands may be nil, because x[k] (or `a, b = array`) gives nil when the element is missing [index-nil]
  hint: check the value first: `if x`, `while x`, `return unless x`, or `x != nil`
  hint: or use Array.fetch / Hash.fetch, which raise instead
```

### `exhaustive`（レベル 3）

開いた型の値が、どのリテラルの分岐にも取られないかもしれない `case`/`in` です。開いた型とは、String、Integer、リテラルで書かれていない Symbol など、値を列挙しきれない型のことです。次のプログラムはレベル 2 までは走ります。

```ruby
def kind(s)
  case s
  in "a" then 1
  in "b" then 2
  end
end
p(kind(String.downcase("A")))  # => 1
```

```
$ bin/sake --strict=3 kind.sake
kind.sake:2:3: error: case/in: no `in` branch matches some values of String [exhaustive]
  hint: add an `else`, or `in` branches for the other values
  hint: reached by the call at line 7
```

### `unrescued`（レベル 4）

rescue されずにトップレベルまで届くかもしれない `raise` です。プログラム向けの項目で、ライブラリの raise は呼び出し側のためのものなので、ライブラリには向きません。

```ruby
def check(n)
  raise ArgumentError, "negative" if n < 0
  n
end
p(check(1))                    # => 1
```

```
$ bin/sake --strict=4 check.sake
check.sake:2:3: error: raise: ArgumentError may reach the top level without being rescued [unrescued]
  hint: rescue it, or check with a level below 4
```

### 項目で選ぶ

レベルの代わりに、項目名で選べます。

- `--strict=type,nil` はその項目だけを選びます。
- `--strict=2,index-nil` はレベルに項目を足します。
- `--strict=3,-index-nil` はレベルから項目を引きます。

各報告は `[type]` のように項目名で終わるので、どの項目を足す・引くかはそこで分かります。

### 報告の性質

- **関数の中のエラー。** 多相な関数の中の報告には、そこに至った呼び出しを示す hint が付きます（上の `half` の例）。
- **到達しない分岐。** 分岐は評価されないので、決して走らない分岐の問題も報告されます（Erlang の Dialyzer と同じ）。
- **内部エラー。** 型推論自体が失敗したときは、警告を出して型検査を飛ばし、プログラムを実行します。
- **要素の組が多すぎるとき。** Array や Tuple の比較（`<`、`<=>`、ソート）は要素型の各組が比較できるか検査します。1 つの比較の要素型の組が 50,000 を超えると、その比較の要素は検査せず、比較の行に警告を出します。他の検査には影響しません。

## 静的エラーの形式

静的エラーは位置順にまとめて報告され、何も実行されません。各行は、ファイル名・行・桁・メッセージの順で、続く `hint:` 行が直し方を示します。

```
FILE:LINE:COLUMN: error: MESSAGE
  hint: SUGGESTION
```

冒頭の `name.upcase` の例では、次のように印字されます。

```
greet.sake:2:11: error: method call on a value `name.upcase` is not allowed
  hint: String.upcase(name)
  hint: Symbol.upcase(name)
```

## 実行時エラーの形式

実行時エラーは、止まった操作の行と、そこに至った呼び出しの列（`from` 行）を印字します。

```
FILE:LINE: in FUNCTION: KIND: MESSAGE
  from FILE:LINE: in CALLER
  hint: SUGGESTION
```

```ruby error
def third(xs) = Array.fetch(xs, 2)
p(third(Any[1, 2]))          # !> IndexError: Array.fetch: index 2 outside of array bounds: -2...2
```

```
third.sake:1: in third: IndexError: Array.fetch: index 2 outside of array bounds: -2...2
  from third.sake:2: in <main>
```

種類の一覧は [例外とエラー](08-exceptions.md) にあります。

# プログラムの構造と名前解決

この章は、プログラムが何から成り、プログラムの中の名前がどう解決されるかを述べます。1 つの考えが全体を貫きます。すべての定義は実行前に集められ、すべての呼び出し先は実行前に決まります。だから関数は定義より上の行から呼べ、名前の誤りは実行前に報告されます。

## ファイルと `require`

プログラムは 1 つのファイルと、それが `require` するファイルです。ファイルのトップレベルには定義と文を並べます。定義は実行前にまとめて集められ、文は上から順に実行されます。

```ruby
puts(greet("Sake"))                  # => Hello, Sake
def greet(name) = "Hello, #{name}"   # 定義より上の行から呼べる
def String.shout(s) = String.upcase(s) + "!"
puts(String.shout("hi"))             # => HI!
Point = Struct.new(:x, :y)
class Point
  def to_s(p) = "(#{@x}, #{@y})"
end
module Util
  module_function
  def origin = Point.new(0, 0)
end
puts(Util.origin)                    # => (0, 0)
```

### トップレベルに書けるもの

- **`require "path"`**: 別のファイルを読みます。**`generate "gen"`** は生成器が印字したソースを繋ぎます。次の節で述べます。
- **関数定義**: `def name(params) ... end` と `def name(params) = expr`。
- **名前空間付きの関数定義**: `def Type.name(params) ...`。`class Type` の中で `name` を定義するのと同じです。
- **名前空間**: `class Name ... end` と `module Name ... end`。
- **クラス**: `attr_*` の行を持つ `class Name`、または `Name = Struct.new(:field, ...)`。
- **文**: それ以外の式。文は順に実行されます。

### `require`

`require "path"` は `path.sake` を読みます。拡張子は省略でき、パスは require するファイルのディレクトリからの相対です。

```ruby
# lib/units.sake
puts("loading units")
def km_to_m(km) = km * 1000
```

```ruby
# main.sake
require "lib/units"          # => loading units
puts("main")                 # => main
puts(km_to_m(3))             # => 3000
```

- **実行前に決まる。** 引数は文字列リテラル、`require` はファイルのトップレベルの文でなければなりません。プログラムを構成するファイルは実行前に決まります。
- **1 回だけ。** 各ファイルは、誰が require しても 1 回だけ読まれます。循環は既に読んだファイルで止まります。
- **glob。** `require "sql/*"` は、require するファイルの隣で `sql/*.sake` に合うファイルを**名前順**に全部読みます（自分自身は除く）。何にも合わなければエラーです。定義は先に集められるので、順序が効くのはトップレベルの文だけです。
- **順序。** require されたファイルのトップレベルの文は、require したファイルの文より先に走ります。1 つのファイルの `require` はすべて先に読まれます。上の例で `loading units` が `main` より先に出るのはそのためです。
- **定義は 1 つの集まり。** すべてのファイルの定義はまとめて集められるので、ファイルをまたいで名前を任意の順で使えます。同じ名前を 2 つのファイルで定義するのは、1 つのファイルの中と同じくエラーです。
- **メッセージ。** エラーメッセージは各行のファイルを名乗ります（`lib/units.sake:4`、`from lib/broken.sake:3`）。
- **ライブラリ。** `require "json"` のように兄弟に無い名前は、処理系に付属する [ライブラリ](10-library.md)（`sakelib/`）から探します。

### `generate`: 実行前に作るコード

Sake は実行中に関数を定義しません。Ruby なら起動時に作るコード（スキーマの列ごとの関数、関数にコンパイルしたテンプレート）は、1 つ前の段で `generate "gen", "arg", ...` が作ります。プログラムを検査する前に、`gen.sake` を独立したプログラムとして検査して走らせ（残りの引数がその `ARGV`）、**それが印字したものを、その位置で require したファイルのようにプログラムに繋ぎます**。そのあと、生成したコードも含めてプログラム全体を検査して走らせます。

```ruby
# gen.sake: cols.txt の各行（"name"、"age"）の読み出し関数
Array.each_with_index(String.lines(File.read("cols.txt"))) do |c, i|
  puts "# sake-origin: cols.txt:#{i + 1}"
  puts "def #{String.strip(c)}(row) = row[#{Kernel.inspect(String.strip(c))}]"
end
```

```ruby
# main.sake
generate "gen"
p(name(Hash.of("name" => "ko1")))
```

- **毎回。** 生成器は起動のたびに走るので、生成したコードは古くならず、常に検査されます。生成器は生成先のプログラムを見られません。同じ生成器と同じ引数は 1 回だけ走ります。
- **`require` と同じ。** 引数は文字列リテラル、`generate` はファイルのトップレベルの文です（それ以外の場所の `generate(...)` は普通の呼び出し）。生成器のファイルは `require` と同じように探します。
- **エラーの位置。** 生成したコードは `(generate at main.sake:2)` と名乗ります。生成器が `# sake-origin: FILE:LINE` の行を書くと、次の同じ行までの行は FILE:LINE（ここでは `cols.txt:1`）として報告されます（静的エラー、実行時エラー、backtrace）。`# sake-origin: none` で終わります。生成器自身の問題や、生成器が終わったエラーは `generate` の行で報告され、何も走りません。
- **見る。** `bin/sake --dump=generated main.sake` が生成したソースを印字します。

### 名前空間: `class` と `module`

`class Name ... end` と `module Name ... end` は名前空間を開きます。`class` は**型**（クラス）を宣言するか、既にある型に操作を足します。`String` のような組み込み型にも足せます。`module` は**型を持たない**名前空間です。

名前空間の本体に書けるのは次だけです。

- `def name(...)`（レシーバ無し）
- `include Module`
- `module_function`（module の中。後述の「module の関数の呼び方」）
- 入れ子の `class` / `module`、`Name = Struct.new(...)`
- 型の別名 `Name = A::B`（後述の「型の別名」）
- class では `attr_reader` / `attr_accessor` / `attr_writer` の行（[クラス](07-classes.md)）

それ以外の文を本体に置くのは静的エラーです。型に `module` を使うのも静的エラーで、hint が `class` を示します。

```ruby error
module String                # !> `module String`: String is a type; add operations to a type with class
  def shout(s) = String.upcase(s)
end
```

### 名前空間は入れ子にできる

`module A` の中の `class B`（`module B`、`B = Struct.new(...)` も）は `A::B` を宣言します。トップレベルの `class A::B` も同じ名前空間を開くので、どちらの書き方でも同じクラスに操作を足せます。

```ruby
module Geo
  Point = Struct.new(:x, :y)
  class Point
    def norm2(p) = @x * @x + @y * @y
  end
  module Util
    module_function
    def origin = Point.new(0, 0)      # ここでの Point は Geo::Point
  end
end
class Geo::Point                       # Ruby の書き方で同じクラスを開く
  def to_s(p) = "(#{@x}, #{@y})"
end
pt = Geo::Point.new(3, 4)
p(Geo::Point.norm2(pt))                # => 25
p(pt.Geo::Point.norm2)                 # => 25
puts(Geo::Util.origin)                 # => (0, 0)
p((pt in Geo::Point))                  # => true
```

- **外からは完全な名前。** `A::B.f(x)`、`x.A::B.f`、`include A::M`、`class C < A::B`、`x in A::B`、`(A::B|C).f(x)`、`rescue A::E` と書きます。
- **中では短い名前。** `A` の中では `B` だけで `A::B` を指せます。Ruby と同じく内側の名前空間から探し、無ければトップレベルの `B` です。
- **`def A::B.f` は書けない。** Ruby の構文に無いからです。入れ子の module の module 関数は、その中で定義します（`module A::B` + `module_function`）。
- **名前空間は値ではない。** `p(A::B)` はエラーで、`A::B` だけを書いても意味がありません。

```ruby error
module Geo
  Point = Struct.new(:x, :y)
end
p(Geo::Point)                # !> type `Geo::Point` cannot be used as a value
```

### 型の別名

`Client = Handshake::Client` は、既にある型（class、module、`Str = String` のような組み込み型）に別の名前を付けます。別名は定数で、スコープは Ruby と同じです。書いた名前空間（トップレベル、または `class` / `module` の本体）に属し、型の名前と同じ規則で探され（内側の名前空間から外へ、最後にトップレベル）、外からは `WebSocket::Client` と書きます。右辺は定数のパスで、別名を書いた場所で解決します。右辺が別名でも構いません。

```ruby
module WebSocket
  module Handshake
    class Client
      attr_reader url
      def host(c) = String.split(@url, "/")[2]
    end
  end
  Client = Handshake::Client           # WebSocket::Client
  module Session
    module_function
    def open(url) = Client.new(url)    # ここでの Client は WebSocket::Client
  end
end
C = WebSocket::Client                  # 別名の別名
c = WebSocket::Session.open("ws://example.com/chat")
p(C.host(c))                           # => "example.com"
p(c.WebSocket::Client.host)            # => "example.com"
p((c in WebSocket::Handshake::Client)) # => true
```

- **名前であって新しい型ではない。** `Client.new`、`Client.f(x)`、`x.Client.f`、`def Client.f`、`include`、`class C < Client`、`in Client`、`rescue Client`、`raise Client`、`Client::Inner` はどれも指す先の型を意味します。メッセージは指す先の型の名前で出ます。未定義の関数の hint は、別名がどの型を指すかを示します。
- **名前空間ごとに 1 つの名前。** その名前空間に同じ名前の型か別名が既にあれば、重複した定義と同じく静的エラーです。別名を通してクラスを定義すること（`class Client::Inner`）もできません。型自身の名前で書きます。
- **型だけ。** 右辺が型を指さないとき、別名が循環するときは静的エラーです。`Pi = Math::PI` はこれまでどおり値の定数です（hint は `def pi = Math::PI`）。

```ruby error
module Net
  class Conn
  end
  Socket = Net::Con          # !> `Socket = Net::Con`: Net::Con is not a type (a constant set to a constant is another name for a class or a module)
end
```

### クラスは継承しない

どの class についても、`class B < A` は A の定義を B に書き写す略記です。その後 A と B は無関係な型で、`A.f` は A の値だけを取ります（[クラス](07-classes.md)）。

```ruby
class A
  attr_reader x
  def double(a) = @x * 2
end
class B < A
  attr_reader y
end
b = B.new(1, 2)
p(B.double(b))               # => 2
p((b in A))                  # => false
```

```ruby error
class A
  attr_reader x
  def double(a) = @x * 2     # !> A.x: argument 1 must be A, but is B [type]
end
class B < A
  attr_reader y
end
p(A.double(B.new(1, 2)))
```

### `self` は無い

`def self.x` は拒否されます。Sake に `self` は無いからです。class の中の `def x` がそのまま `A.x` を定義します。

```ruby error
class A
  attr_reader x
  def self.make = A.new(1)   # !> `def self.make` inside `A`: write `def make` (it defines A.make)
end
```

### 同じ名前は 1 度だけ

1 つの名前空間で同じ名前を 2 度定義するのはエラーです。組み込みの操作を再定義するのもエラーです。

```ruby error
def f = 1
def f = 2                    # !> `f` is already defined at line 1
```

```ruby error
def String.upcase(s) = s     # !> `String.upcase` is a built-in operation and cannot be redefined
```

### 値の定数は無い

定数に代入できるのは `Struct.new`（と `Exception.new`）か、型の名前（上の型の別名）だけです。名前付きの値は関数にして（`def pi = 3.14159`）呼びます（`pi`）。`PI = 3.14` は静的エラーで、hint がその関数を示します。`PI` を使う各行にも、`pi` と呼ぶ hint が付きます。1 度だけ計算する値には `once { ... }` があります（[組み込み操作](09-builtins.md)）。

```ruby
def pi = 3.14159
p(pi * 2)                    # => 6.28318
```

```ruby error
PI = 3.14                    # !> Sake has no value constants; a constant names a class (`Point = Struct.new(:x, :y)`, `Err = Exception.new(:msg)`), and a value goes in a function
p(PI * 2)                    # !> `PI` is not defined (Sake has no value constants)
```

## 型付きの呼び出し

`Type.op(args...)` は名前空間 `Type` の操作 `op` を呼びます。慣習として、主語（subject）が第 1 引数です。`Type` と `op` の両方が存在しないとプログラムは実行前に拒否されます。エラーは綴りの候補と、`op` を定義している他の名前空間を示します。

```ruby error
puts(String.upcse("a"))      # !> undefined function `String.upcse`
```

```ruby error
puts(Strng.upcase("a"))      # !> undefined type or module `Strng`
```

```ruby error
puts(Integer.upcase("a"))    # !> undefined function `Integer.upcase`
```

最後の例の hint は `` `upcase` is defined in `String.upcase`, `Symbol.upcase` `` です。

## 連鎖と `_`

一連の操作を左から右・上から下に読める形が 2 つあります。どちらも、どの型の操作かは同じ行で分かります。

### 連鎖

`x.T.f(args...)` は `T.f(x, args...)` です。段 `.T` が型かモジュールを名乗り、その左の値が第 1 引数になります。段は続けて書け、次の行の先頭にドットを置くこともできます。

連鎖は `T.f(x)` で始めます。続く段は、値の型が同じなら `.g`、変わるなら `.U.g` と書きます（[型を省いた段](#型を省いた段)）。変数から始める `x.T.f` も書けますが、型の名前が行の途中に挟まって読みにくいので勧めません。検査器の hint も示しません。

```ruby
line = "a, b ,c"
r = String.split(line, ",")
  .Array.map { |s| String.strip(s) }
  .join("|")
p(r)                         # => "a|b|c"
```

### 型を省いた段

連鎖の段で型を省くと、その連鎖が最後に名乗った型を引き継ぎます。`String.strip(s).upcase` は `String.strip(s).String.upcase` で、その次の段も String を引き継ぎます。型を書くのは、連鎖の始まりと、値の型が変わる段だけです。

```ruby
xs = Any[3, 1, 2]
p(Array.sort(xs).reverse.first(2))           # => [3, 2]
p(String.strip("  ab ").upcase.reverse)      # => "BA"
words = Any["b", "a", "b"]
p(Array.tally(words).Hash.keys.Array.sort)  # => ["a", "b"]
```

最後の例は、`Array.tally` が Hash を返すので `.Hash.keys` と名乗り直し、`Hash.keys` が Array を返すので `.Array.sort` と名乗り直しています。

引き継ぐ型は、同じ行を左に読めば分かります。値の型を見て選ぶのではありません。レシーバが変数やリテラルなら型を名乗っていないので、`x.f` は今までどおり静的エラーです。

- **引き継いだ型にその操作が無い**と静的エラーです。hint は、その名前を持つ型で名乗り直した形を示します。
- **値が引き継いだ型でない**と型エラーです（`T.f(r)` と書いたときと同じ）。hint は、値の型で名乗り直した形を示します。

```ruby error
counts = Hash.of("a" => 2, "b" => 1)
p(Hash.sort_by(counts) { |k, n| n }.first)  # !> Hash.first: argument 1 must be Hash, but is Array
```

`Hash.sort_by` は Array を返すので、`.Array.first` と名乗り直します。

操作の無い `x.T` は静的エラーです。

```ruby error
s = "x"
p(s.String)                  # !> `s.String` needs an operation after the type: `s.String.op(...)`
```

### `_`

`_` は、同じ本体（関数、ブロック、分岐、トップレベル）の**直前の文**の値です。

```ruby
line = "a, b ,c"
String.split(line, ",")
Array.map(_) { |s| String.strip(s) }
Array.join(_, "|")
p(_)                         # => "a|b|c"
```

`_` が指すのが式ではなく文なのは、文が曖昧でないからです。式レベルの `_` は、前の行に含まれる部分式のどれかを選ばなければならず、その選び方に自然な答えはありません。「直前の文」なら 1 つに決まります。

- **最初の文では読めない。** 本体の最初の文や、定義の直後で `_` を読むのは静的エラーです。
- **括弧と補間。** 括弧の中と文字列の補間の中では、最初の文は外側の文の `_` を読みます。
- **名前としての `_`。** `_` は無視する名前としては使えます（`|_, v|`、`a, _ = t`）。ただし、ローカル変数を名付けた `_` は読めません。

```ruby
String.upcase("sake")
puts("got #{_}")             # => got SAKE
Any[1, 2]
p((Array.size(_) + 1))       # => 3
```

```ruby error
def f(x)
  p(_)                       # !> `_` is the previous statement's value, and no statement precedes it here
end
f(1)
```

```ruby error
a, _ = [1, 2]
p(_)                         # !> `_` is the previous statement's value, but here it names a local variable
```

## 値へのメソッド呼び出しは無い

小文字のレシーバを持つ呼び出し、`x.op(...)`、`"lit".op`、`3.times` は静的エラーです。エラーは型付きの形を提案し、レシーバが型を名乗らない呼び出し（`f(x).op`）なら連鎖の形（`f(x).T.op(...)`）も提案します。レシーバが型を名乗る呼び出しなら、エラーではなく型を引き継ぐ段です。

```ruby error
s = " a "
puts(s.strip.upcase)         # !> method call on a value `s.strip.upcase` is not allowed
```

- **連鎖**は全体を書き直します。`s.strip.upcase` には `String.strip(s).upcase` を提案します。最初の段が `T.f(x)` になり、後の段は同じ型なら型を省き、違う型なら名乗ります。
- **フィールドアクセス**にはリーダを提案します。`p.x` には `Point.x(p)`、`p.x = v` には `p.Point.x = v` です。関数のセッタなら `Point.set_x(p, v)` と書きます。
- **リテラルのレシーバ**は候補をそのリテラルの型に絞ります。`"lit".upcase` には `String.upcase("lit")` だけです。
- **`x.nil?`** には `x == nil` を提案します。

```ruby error
Point = Struct.new(:x, :y)
pt = Point.new(1, 2)
p(pt.x)                      # !> method call on a value `pt.x` is not allowed
```

```ruby error
3.times { puts("hi") }       # !> method call on a value `3.times` is not allowed
```

## 型を付けない呼び出し

レシーバ無しの `f(args)` は実行前に解決されます。次の順に探し、最初に見つかったものが勝ちます。

1. 囲んでいる class か module。その組み込みの操作、フィールドの reader と writer、include した関数を含みます。一番内側のものだけで、`A::B` の中から `A` の関数は `A.f(...)` と呼びます（型の名前は関数と違って外側へ探します）。
2. トップレベルの関数。
3. `Kernel`（`puts`、`print`、`p`）。

```ruby
def size(x) = "top-level size"
class Box
  attr_reader items
  def size(b) = Array.size(@items)
  def describe(b) = "#{size(b)} items"   # Box.size
end
b = Box.new(Any[1, 2])
puts(Box.describe(b))        # => 2 items
puts(size(b))                # => top-level size
```

- **隠す。** 内側の定義は外側を隠します。同じ名前が複数の段にあるのはエラーではありません。
- **外側は名前空間付きで。** 外側の定義は常に名前空間付きで呼べます（`Kernel.puts`）。
- **トップレベル。** トップレベルのコードには囲む名前空間が無いので、解決は 2 から始まります。

```ruby
class Logger
  attr_reader prefix
  def puts(l, msg) = Kernel.puts("#{@prefix}#{msg}")
  def run(l) = puts(l, "start")          # Logger.puts
end
Logger.run(Logger.new("> "))             # => > start
puts("done")                             # => done
```

## include

class か module の本体の `include M` は、module `M` の関数を include した側に書き写します。Ruby の module を静的に解決したものです。

```ruby
module Summary
  def total(x) = Array.inject(items(x), 0) { |a, v| a + v }
  def report(x) = "total=#{total(x)}"
end
class Basket
  include Summary
  attr_reader items
end
b = Basket.new(Any[1, 2, 3])
puts(Basket.report(b))       # => total=6
puts(Summary.total(b))       # => 6
```

### 写し

`M` の各関数 `f` は、include した名前空間 `X` の `X.f` になります。`X` が既に `f` を持つならそれが勝ちます。`M` が include した module も写します。

```ruby
module A
  def bar(x) = "A"
  def baz(x) = "A"
end
class C
  include A
  attr_reader v
  def bar(x) = "C"
end
p(C.bar(C.new(1)))           # => "C"
p(C.baz(C.new(1)))           # => "A"
```

### 順序

Ruby の祖先順で探します。**最後**に include した module が先です。`include A` の後に `include B` なら、両方にある `bar` は B のものです。

```ruby
module A
  def bar(x) = "A"
end
module B
  def bar(x) = "B"
end
class C
  include A
  include B
  attr_reader v
end
p(C.bar(C.new(1)))           # => "B"
```

### include 側での解決

写した関数の中の型無しの名前は `X` で解決されます。だから `M` は、`X` が提供する関数（`each` など）を使えます。実行時のディスパッチは無く、各 `X.f` は実行前に固定されます。`X` がクラスなら `@x` は `X` のフィールドです。

```ruby
module Named
  def label(x) = "<#{@name}>"
end
class Cat
  include Named
  attr_reader name
end
puts(Cat.label(Cat.new("tama")))   # => <tama>
```

### 要件

`M` の関数の本体で型を付けずに呼ぶ名前（`each(x)` など）と `@x` のうち、`M` 自身もトップレベルも `Kernel` も定義しないものが、`M` の要件です。宣言はなく、本体から集められます。

- **include 側に無い。** 要件を `X` が持たないと（`each` が無い、フィールド `x` が無い）、`include M` は静的エラーです。どの関数が何を必要としたかを名指しします。
- **直接呼ぶ。** 要件を持つ関数を、include した型を通さずに `M.total(x)` と直接呼ぶのも静的エラーです。hint は include した型を通して呼ぶ形を示します。これは `total` が module 関数のときの話で、mixin 関数の `M.total(x)` は次の節のディスパッチです。

```ruby error
module Summary
  def total(x) = Array.inject(items(x), 0) { |a, v| a + v }
end
class Empty
  include Summary            # !> `include Summary` in Empty: Summary.total needs `items`, which Empty does not define (used at line 2)
  attr_reader v
end
```

```ruby error
module Summary
  module_function
  def total(x) = Array.inject(items(x), 0) { |a, v| a + v }
end
class Basket
  include Summary
  attr_reader items
end
puts(Summary.total(Basket.new(Any[1])))   # !> Summary.total needs `items` from a namespace that includes Summary
```

### 制限

- include できるのは module だけです。class を include するのは静的エラーです。
- include の循環はエラーです。
- **継承ではない。** `include` は部分型関係を作りません。`M` を include した値は、`M` の値になるわけではありません。

```ruby error
class A
  attr_reader x
end
class B
  include A                  # !> `include A`: A is not a module
  attr_reader y
end
```

## module の関数の呼び方: module_function とディスパッチ

型や module の 1 つの名前は 1 つの関数です。Sake には `def f` の隣の `def self.f` はありません。「インスタンス」の形は、値が先に来る（`T.f(x, ...)`）という意味しか持たないからです。Ruby でクラスメソッドとインスタンスメソッドが同名のとき（`Net::HTTP.get(uri)` と `http.get(path)`）は、片方に別の名前を付けるか、1 つの関数が第 1 引数の型で形を見分けます。

module の関数は Ruby と同じく 2 種類あります。

| 種類 | 宣言 | `M.f(args)` |
|---|---|---|
| module 関数 | `module_function` の後、`module_function :f`、または `def M.f` | `M` 自身の `f` が走る（静的） |
| mixin 関数 | それ以外の module の関数 | **ディスパッチ**: 第 1 引数の型の `f` が走る。その型は `M` を include していなければならない |

```ruby
module Describe
  def describe(x) = "#{prefix}#{name(x)}"   # mixin 関数
  def prefix = "* "
  module_function :prefix                   # module 関数
end
class Cat
  include Describe
  attr_reader name
end
class Dog
  include Describe
  attr_reader name
end
p(Describe.prefix)                          # => "* "
puts(Describe.describe(Cat.new("tama")))    # => * tama
puts(Describe.describe(Dog.new("pochi")))   # => * pochi
puts(Cat.describe(Cat.new("tama")))         # => * tama
```

### 主語が無い

mixin 関数は引数無しで呼べません（`M.foo`）。ディスパッチするものが無いからです。どの型も `M` を include していないときに呼ぶのも静的エラーで、`module_function` を使う hint が付きます。

```ruby error
module Greeting
  def hello(x) = "hello"
end
puts(Greeting.hello(1))      # !> Greeting.hello is a mixin function, and no type includes Greeting
```

### 型検査

第 1 引数が取りうる型のすべてが `M` を include することを型推論が検査し、していないものを `type` の問題として報告します。実行時は、include していない型は `TypeError` を投げます。

```ruby error
module Describe
  def describe(x) = "#{name(x)}"
end
class Cat
  include Describe
  attr_reader name
end
Dog = Struct.new(:name)
def pick(flag) = flag ? Cat.new("tama") : Dog.new("pochi")
puts(Describe.describe(pick(true)))   # !> Describe.describe dispatches on its first argument, which can be Dog; the types that include Describe are Cat [type]
```

### 静的な呼び出し

型自身の名前空間は常に静的です。上の例の `Cat.describe(c)` は Cat の `describe`（`Describe` から写したもの）を走らせ、`Describe.describe(x)` がディスパッチする形です。

### Kernel

すべての型は `Kernel` を include します。`Kernel.to_s(x)` と `Kernel.inspect(x)` は型自身の `to_s` / `inspect` にディスパッチし、無ければ組み込みの形を使います。`"#{x}"`、`puts`、`p` はその略記です。

```ruby
class Temp
  attr_reader deg
  def to_s(t) = "#{@deg} C"
end
t = Temp.new(20)
puts(t)                      # => 20 C
puts("now #{t}")             # => now 20 C
puts(Kernel.to_s(t))         # => 20 C
p(Kernel.to_s(5))            # => "5"
```

### 必須の関数

本体が `raise NotImplementedError` だけ（メッセージの有無は問わない）の module の関数は必須です。module を include する各型がそれを定義し、`M.f(x)` はその定義にディスパッチします。ブロックを取るかは型側の定義から決まります。

```ruby
module Shape
  def area(s) = raise NotImplementedError
  def describe(s) = "area=#{area(s)}"
end
class Sq
  include Shape
  attr_reader side
  def area(s) = @side * @side
end
puts(Shape.describe(Sq.new(3)))   # => area=9
puts(Shape.area(Sq.new(2)))       # => 4
```

- **定義しない型。** 定義せずに include した型は、呼び出しが届きうる場所で `type` の問題になり、実行時は `NotImplementedError` です。
- **rescue できない。** `NotImplementedError` はプログラムの誤りで rescue できません。
- **メッセージ。** `raise T` と例外型だけ書くと、型名がメッセージになります。

```ruby error
module Shape
  def area(s) = raise NotImplementedError
  def describe(s) = "area=#{area(s)}"   # !> Shape.area: Blob includes Shape but does not define area, which Shape requires (`raise NotImplementedError`) [type]
end
class Blob
  include Shape
  attr_reader v
end
puts(Shape.describe(Blob.new(1)))
```

## 型を列挙する: `(A|B).f(x)`

`(A|B).f(x, args...)` は、`x` が取りうる型を操作自身に列挙します。実行時は `x` の型が `A.f` か `B.f` を選び、それ以外の型は `TypeError` です。結果は結果の和です。

```ruby
Leaf = Struct.new(:weight)
Node = Struct.new(:weight, :kids)
def weight(t) = (Leaf|Node).weight(t)   # 2 つのクラスの同名のフィールド
p(weight(Leaf.new(2)))                  # => 2
p(weight(Node.new(5, Any[])))         # => 5
def size_of(x) = (String|Array|Hash).size(x)
p(size_of("abc"))                       # => 3
p(size_of(Any[1, 2]))                 # => 2
```

実行前には 2 つのことが検査されます。

- **列挙した型は `f` を持つ。** 持たなければ静的エラーです。
- **列挙にない型は来ない。** 列挙にない型の値が届きうると、検査器が `type` の問題として報告します。

```ruby error
def shout(x) = (String|Integer).upcase(x)   # !> Integer has no `upcase`, so `(String|Integer).upcase` cannot dispatch to it
p(shout("abc"))
```

```ruby error
def size_of(x) = (String|Array).size(x)   # !> (String|Array).size: argument 1 must be String or Array, but is Integer [type]
p(size_of(5))
```

- **列挙できるのは型。** 組み込み型（`IO` も）とクラスを、それぞれ 1 度まで。`nil` は列挙できません。先に nil を検査します。
- **形は違ってよい。** 列挙した関数の形は違っていてよく、ユーザ関数の `*rest` はその分岐のために詰められます（`(IO|StringIO).print(io, a, b)`）。キーワードを取る関数は列挙できません。`case` で型を見分けてください。
- **mixin のディスパッチとの関係。** mixin 関数のディスパッチ `M.f(x)` は、`M` を include するクラスをすべて列挙した `(A|B|...).f(x)` と同じ振り分けです。違いは集合の述べ方で、`include` が各クラスの側で宣言するのに対し、`(A|B)` は呼び出しの場が述べます。だから宣言が要らず、module を共有しない型（組み込み型、同名のフィールド）にも使えます。

## 引数の数とブロック

呼び出し先が実行前に決まるので、引数の数とブロックの有無は実行前に検査されます。

- **引数の数。** ユーザ関数も組み込みの操作も検査されます。
- **ユーザ関数へのブロック。** 関数が `yield` を含む（または `&b` を取る）とき**に限り**ブロックを渡します。ただし `block_given?` を検査する関数はブロック無しで呼べます。
- **組み込みへのブロック。** 組み込みの操作はブロックを必須とするか拒否します。

```ruby error
def area(w, h) = w * h
p(area(3))                   # !> wrong number of arguments for area (given 1, expected 2)
```

```ruby error
def twice(x) = x * 2
p(twice(3) { 1 })            # !> twice does not take a block (it has no `yield`)
```

```ruby error
p(Array.map(Any[1]))       # !> Array.map requires a block
```

### スプラット引数

`*xs` は Tuple か Array を展開します。他の値は `TypeError` です。展開先は rest 引数だけです。組み込みのもの（`puts(*lines)`、`format(fmt, *row)`、`Any[*xs, 0]`、`Set.of(*xs)`、`Array.push(a, *xs)`）か、ユーザ関数の `*rest`（`join(*parts)`、[関数とブロック](04-functions.md)）です。

```ruby
def join(sep, *parts) = Array.join(parts, sep)
xs = Any["a", "b"]
p(join("-", *xs))            # => "a-b"
t = [1, 2]
p(Any[*t, 0])              # => [1, 2, 0]
puts(*xs)                    # => a
                             # => b
```

- **前の引数は書き切る。** スプラットの前の引数は 1 つずつ書くので、その数は検査されます。
- **静的エラー。** `*rest` の無い関数へのスプラットと、必須か省略可能な引数を埋めるスプラットは静的エラーです。`Array.zip` / `Range.zip`（Tuple の長さが引数の数）と `Hash.of(...)` へのスプラットも同様です。
- **型推論。** Tuple は位置ごとに展開され、Array は要素型の任意個の引数を表します。

```ruby error
def two(a, b) = a + b
t = [1, 2]
p(two(*t))                   # !> `*t`: splat arguments go only to a `*rest` parameter or to built-ins that take any number of arguments (puts, format, Any[...], Set.of, Array.push, ...)
```

# 値と型

Sake の値は Ruby の値とほぼ同じ顔をしていますが、どの値も 1 つの型タグを持ち、すべての操作がそれを検査します。この章は、どんな型があり、それぞれをどう書くかを述べます。Ruby と字面が同じで意味が違うのは `[a, b]`（Tuple）、`{x: 1}`（Record）、`{}` と `{k => v}`（静的エラー）です。

| 型 | 書き方（リテラル、または値を作る操作） | 備考 |
|---|---|---|
| Integer | `42`, `-7` | 多倍長（インタプリタ。幅は処理系ごと: C・Rust への変換は 64 ビットで、溢れるとエラー） |
| Float | `1.5`, `2.0` | |
| String | `"abc"`, `'abc'`, `"a#{x}"` | 補間は `to_s` を使う（下記「値の表示」） |
| true / false | `true`, `false` | 内部では 1 つの型 `Boolean`。ソースには書けない |
| nil | `nil` | 「nil」の節を参照 |
| Tuple | `[a, b, ...]` | 長さと位置ごとの型が作成時に固定 |
| Record | `{x: a, y: b}` | (フィールド, 型) の集合が作成時に固定 |
| Array | `Any[a, ...]` | 要素型の宣言なし |
| T の Array | `T[a, ...]`、例 `Float[]`, `Point[p]` | 要素型 T。書き込みごとに検査 |
| Hash | `Hash.of("a" => 1, b: 2)`, `Hash.new(0)` | キーは値と型で比較（Ruby の `eql?`） |
| Set | `Set.of(1, 2)` | 要素は値と型で比較（Ruby の `eql?`） |
| Symbol | `:name` | |
| Range | `1..5`, `1...5`, `1..` | 端は Integer, Float, String, nil |
| Regexp, MatchData | `/(\d+)-(\d+)/`, `/#{x}/`, `String.match(s, re)` | |
| Rational, Complex | `2r`, `1/3r`, `Rational(1, 3)`, `2i`, `Complex(1, 2)` | Ruby の数値の塔 |
| Time | `Time.now`, `Time.at(0)`, `Time.new(2026, 10, 1)` | |
| IO | `IO.stdout`, `File.open(path)` | ファイルとストリームの 1 つの型 |
| Thread, Mutex, Queue, TCPServer, Socket | `Thread.new { }`, `Mutex.new`, ... | 並行とネットワーク |
| クラス | `Point.new(x, y)` | 可変なフィールドを持つレコード（[クラス](07-classes.md)） |

- **真偽。** 偽は `nil` と `false` だけです。`0` や `""` を含む他のすべての値は真です。
- **エラーメッセージ。** `nil`、`true`、`false` は値として示され（`got nil`）、他の値は型名で示されます（`got Integer`）。

```ruby
p(0 ? "yes" : "no")            # => "yes"
p("" ? "yes" : "no")           # => "yes"
p(nil ? "yes" : "no")          # => "no"
p(false ? "yes" : "no")        # => "no"
```

## 値の表示

どの値も 2 つの形で表示できます。`to_s` は人に読ませる形、`inspect` はプログラマに値の種類まで見せる形で、使い分けは Ruby と同じです。

| 形 | 使う場所 | 組み込みの形 |
|---|---|---|
| `to_s` | `puts`, `print`, `"#{x}"`, `Array.join`, `format` の `%s`, `:"#{x}"`, `/#{x}/` | Ruby の `to_s` と同じ。`nil` は空、Array と Tuple は `inspect` |
| `inspect` | `p`、`Kernel.inspect`、`format` の `%p`、および Array・Tuple・Hash・Record の中の要素 | Ruby の `inspect` と同じ。`#<struct Point x=1, y=2>` |

```ruby
Point = Struct.new(:x, :y)
puts("a")                      # => a
p("a")                         # => "a"
puts("#{nil}|")                # => |
puts("#{[1, "a"]}")            # => [1, "a"]
puts(format("%s %p", "a", "a"))  # => a "a"
p(Point.new(1, 2))             # => #<struct Point x=1, y=2>
```

### 自分の形

クラスはその本体に自分の `to_s` と `inspect` を定義できます。必須の引数は値 1 つで、String を返さなければなりません。既定値付きの引数は続けられます（`to_s(n, base = 10)`）。

```ruby
class Point
  attr_accessor x, y
  def to_s(p) = "(#{@x}, #{@y})"
  def inspect(p) = "Point(#{@x}, #{@y})"
end
pt = Point.new(1, 2)
puts(pt)                       # => (1, 2)
puts("at #{pt}")               # => at (1, 2)
p(pt)                          # => Point(1, 2)
p([pt])                        # => [Point(1, 2)]
```

String でない結果は、実行前に `type` の問題として報告されます。実行時に届けば `TypeError` です。

```ruby error
class Point
  attr_accessor x, y
  def to_s(p) = @x
end
puts(Point.new(1, 2))          # !> Point.to_s must return a String, but returns Integer [type]
```

- **どれが走るか。** 型の集合は閉じているので、値の型が分かればどの `to_s` が走るかも分かります。

## Tuple、Record、Array

リテラル `[...]` と `{...}` には型を付けた操作が無いので、その**形**が作成時に型を決めます。`[a, b]` は Tuple、`{x: a, y: b}` は Record です。伸びる容器は、型を付けた操作（`Any[...]`、`T[...]`、`Hash.of(...)`）で作ります。

### リテラルの性質

- **中身は可変。** リテラルの中身は同じ型の値で置き換えられ、各書き込みが検査されます。Tuple は `t[i] = v` で書きます。Record に書く構文はまだありません。
- **長さは固定。** 長さは型の一部なので、空の `[]` は伸びません。
- **nil。** `nil` で作った位置の型は nil で、後から他の値を入れられません。後で値を入れる場所には、`0` や `""` のような意図した型の仮の値を置きます。

```ruby error
xs = []
Array.push(xs, 1)              # !> `[...]` is a Tuple with a fixed length; for a growable Array, write `Any[...]`
```

```ruby error
t = [1, nil]
t[1] = 2                       # !> Indexable.[]=: the value must be Nil, but is Integer [type]
```

### Tuple

リテラル `[a, b, ...]` は Tuple です。要素は多重代入 `x, y = t` か添字 `t[0]` で読みます。

```ruby
t = [1, "a"]
x, y = t
p(x)                           # => 1
p(y)                           # => "a"
t[0] = 2
p(t)                           # => [2, "a"]
p(Tuple.size(t))               # => 2
p(Tuple.max([3, 9, 4]))        # => 9
```

- **多重代入。** `x, y = t` は Tuple を分解します。Array も分解します（`key, value = String.split(s, "=")`）。Ruby と同じく、足りない要素は nil、余った要素は捨てられます。
- **足りないかもしれない要素。** それを受ける変数は `x[k]` と同じ `nil | T` の型です（`index-nil` 項目、レベル 3）。
- **代入先。** 要素とフィールドも書けます。`a[i], a[j] = a[j], a[i]` は交換、`@done, @rest = Array.partition(xs) { ... }` はフィールドへの代入です。レシーバと添字を先に、右辺をその後に評価します。
- **残りを受ける。** `first, *rest = xs` は残りを新しい Array に入れます。`a, *mid, z = xs` も同じで、`x, * = xs` は残りを捨てます。rest を受けられるのはローカル変数だけです。
- **`[...]` の中のスプラット。** Tuple の長さは既知でなければならないので、`[*xs, 1]` は拒否されます。`Any[*xs, 1]` は Array を作ります。
- **添字。** `t[0]` は位置を読み、`t[0] = v` は同じ型の値で置き換えます。
- **操作。** `Tuple.size` と `Tuple.length` が要素数です。`Tuple.max([a, b])` は Ruby の `[a, b].max` です。長さが分かるので nil にはなりません。

```ruby
first, *rest = Any[1, 2, 3]
p(first)                       # => 1
p(rest)                        # => [2, 3]
key, value = String.split("a=1", "=")
p(value)                       # => "1"
a = Any[1, 2]
a[0], a[1] = a[1], a[0]
p(a)                           # => [2, 1]
```

### Record

リテラル `{x: a, y: b}` は Record です。フィールド名で読む、小さな固定の値の組です。

- **型。** Record の型は (フィールド, 型) の集合、例えば `{x: Integer, y: Integer}` です。同じ集合の Record は同じ型です。
- **順序。** 順序は関係ありません。`{y: 2, x: 1}` は `{x: 1, y: 2}` と印字され、両者は `==` です。
- **クラスの値ではない。** フィールドが一致しても Record はクラスの値ではありません。クラスは名前で、Record 型は構造で決まります。
- **フィールドの読み出し。** パターンで分解します: `r => {x:, y: name}`。ローカル `x` にフィールド `x`、ローカル `name` にフィールド `y` が束縛されます。一部のフィールドだけ書いてもよい。`Record.to_h(r)`、`Record.keys(r)`、`Record.values(r)` もあります。
- **無いフィールド。** 実行前に `type` で報告されます。実行時に届けば、無いフィールドは `KeyError`、Record でない値は `TypeError` です。
- **制限。** フィールド名はラベル（`x:`）で書きます。空の `{}` と `{key => value}` は静的エラーです（Hash は `Hash.of(...)`）。

```ruby
Point = Struct.new(:x, :y)
r = {y: 2, x: 1}
p(r)                           # => {x: 1, y: 2}
p(r == {x: 1, y: 2})           # => true
p(r == Point.new(1, 2))        # => false
r => {x:, y: name}
p(x)                           # => 1
p(name)                        # => 2
p(Record.keys(r))              # => [:x, :y]
```

```ruby error
r = {x: 1}
r => {z:}                      # !> the pattern needs field `z`, but the value is {x: Integer} [type]
```

```ruby error
h = {"a" => 1}                 # !> `{"a" => ...}` is not a Hash in Sake: `{name: value}` makes a Record
```

### Array

`Any[a, ...]` は要素型を宣言しない Array を作ります。どの値も入ります。Array は可変で、参照で共有されます。`Any` は prelude が Kernel に付けた名前（`Any = Kernel`）です。どの型も Kernel を include しているので、その Array はどの値も受けます。`Array[...]` はこの Array ではなく、下の `T[...]` と同じく Array の Array です。

### T の Array

`T[a, ...]` は、どの T でも要素型 T の Array を作ります。T は組み込み型（`Integer`, `Float`, `Rational`, `Complex`, `String`, `Symbol`, `Tuple`、そして `Array`, `Hash`, `Set`。これらの `[...]` は Array の Array、Hash の Array、Set の Array）、クラス、またはモジュールです。Hash そのものは `Hash.of(k => v)` か `Hash.new`、Set は `Set.of(a, b)` か `Set.new(xs)` で作ります。モジュールの Array `M[...]` には M を include した型の値が入り、各要素に mixin 関数 `M.f(x)` を使えます。

- **書き込みの検査。** 作成、`Array.push`、`Array.append`、`Array.concat` のすべての書き込みが検査され、合わなければ `TypeError`。暗黙の変換は無く、Integer は `Float[]` に入りません。
- **静的検査。** `T[...]` のリテラル引数が別の型なら実行前に報告されます。Ruby 流に書いた `Point[1, 2]`（`Point.new(1, 2)` のつもり）がここで捕まります。
- **型無しの結果。** `map`、`select`、`sort` などが返す Array は要素型を宣言しません。

```ruby error
fs = Float[1.5]
Array.push(fs, 2.5)
Array.push(fs, 3)              # !> Array.push: an element must be Float, but is Integer [type]
```

```ruby error
Point = Struct.new(:x, :y)
pt = Point[1, 2]               # !> Point.new(1, 2) creates one Point; Point[...] is an Array of Point
```

```ruby
Point = Struct.new(:x, :y)
pts = Point[Point.new(1, 2), Point.new(3, 4)]
xs = Array.map(pts) { |pt| Point.x(pt) }
Array.push(xs, "s")
p(xs)                          # => [1, 3, "s"]
```

```ruby
module Shape
  def area(s) = raise NotImplementedError
end
class Sq
  include Shape
  attr_reader n
  def area(s) = @n * @n
end
class Rect
  include Shape
  attr_reader w, h
  def area(s) = @w * @h
end
shapes = Shape[Sq.new(2), Rect.new(2, 3)]
p(Array.map(shapes) { |s| Shape.area(s) })   # => [4, 6]
```

### Ruby の癖

- **Array が要るところの `[]`。** Array が要るところに Tuple や Record を渡す（`result = []` の後の `Array.push(result, x)`）と、`Any[]` と書く hint 付きで失敗します（上の例）。
- **要素型を変える in-place 操作。** 検査器は容器にプログラム全体で 1 つの要素型を与えます。そのため `Array.map!(xs) { |x| Integer.to_s(x) }` や `Hash.transform_keys!(h) { ... }` の後は、容器が古い型と新しい型の両方を持つとみなし、片方にしか合わない操作を `type`（部分的）として報告します。in-place の形は 1 つの型の中の写像に使い、型を変えるときは `Array.map` / `Hash.transform_keys`（新しい容器）を使ってください。

```ruby error
xs = Any[1, 2]
Array.map!(xs) { |x| Integer.to_s(x) }
p(Array.sum(xs))               # !> Array.sum: an element must be Integer|Float|Rational|Complex, but can be String [type]
```

## Hash と Set

Hash と Set は、キーや要素を値で探す伸びる容器です。リテラル `{...}` は Record なので、どちらも型を付けた操作で作ります。

### 構築

`Hash.of(k => v, ...)`、`Hash.new`、`Hash.new(default)` が Hash を、`Set.of(x, ...)` が Set を作ります。`Hash.of(name: v)` と書くとキーは Symbol です。

```ruby
h = Hash.of("a" => 1, b: 2)
p(h)                           # => {"a" => 1, b: 2}
counts = Hash.new(0)
Array.each(String.split("the cat the", " ")) { |w| counts[w] += 1 }
p(counts)                      # => {"the" => 2, "cat" => 1}
Hash.each(counts) { |k, v| puts("#{k}: #{v}") }   # => the: 2
                                                  # => cat: 1
```

### キーと要素の比較

Hash のキーと Set の要素は Ruby の `eql?` と同じく、値と型で比較します。`1` と `1.0` は別のキーですが、`1 == 1.0` は true です。

```ruby
p(Hash.of(1 => "a")[1.0])         # => nil
p(Set.of(1, 1.0))                 # => Set[1, 1.0]
p(1 == 1.0)                    # => true
```

- **使えるもの。** Integer, Float, String, Symbol, true, false, nil, Time、およびそれらからなる Tuple, Record, Array, Hash, Set、クラスの値。
- **使えないもの（`TypeError`）。** Regexp、Range、自分の等価（`==`、または `Comparable` の `<=>`）を定義したクラスの値。キーの比較がその等価と食い違いうるからです。
- **キーの変更。** Ruby と同じく、キーに使った Array・Hash・Set・クラスの値を後で変えると見つからなくなります。
- **キーは複製される。** Tuple や Record のキーは格納時に複製されるので、元を後で書いてもキーは変わりません。

```ruby error
h = Hash.of(/a/ => 1)             # !> Regexp cannot be a Hash key or Set element
```

```ruby
k = [1, 2]
h = Hash.of(k => "a")
k[0] = 9
p(Hash.keys(h))                # => [[1, 2]]
```

### 既定値

`Hash.new(default)` は無いキーに `default` を返し、Ruby と同じく同じオブジェクトを共有します。ブロックの形 `Hash.new { ... }` はありません（ブロックは値ではない）。

```ruby
h = Hash.new(Any[])
Array.push(h[:a], 1)
p(h[:b])                       # => [1]
```

```ruby error
h = Hash.new { |hh, k| 0 }     # !> Hash.new does not take a block
```

### ブロックと順序

- **ブロック。** Hash のブロックは `[key, value]` を 1 つの Tuple として受けるので、`|k, v|` で分解します（上の `Hash.each` の例）。
- **順序。** 反復は挿入順です。

## nil

`nil` は普通の値です。無いかもしれない値の型は `nil | T` で、Option のような包みはありません。nil を受け取れない操作に渡す前に、検査で型から nil を取り除きます。

### 実行時

T が要る操作が `nil` を受けると `TypeError ... got nil` を投げます。インタプリタはそのエラーの経路でだけ静的解析を走らせ、nil を持ちうるフィールドと nil を格納する行を hint に加えます。

```ruby error
h = Hash.of("a" => "x")
puts(String.upcase(h["b"]))    # !> TypeError: String.upcase: argument 1 must be String, got nil
```

### 絞り込み

静的解析は**ローカル変数**を次の場所で絞ります。

| 形 | `x` が絞られる場所 |
|---|---|
| `if x` / `while x` / `x && …` | `x` が真のときに取る分岐で非 nil |
| `x != nil` / `x == nil` | 対応する分岐で nil または非 nil |
| `!x` / `unless x` | 同じ、分岐を入れ替えて（`if !x … else` の else で非 nil） |
| `return unless x`、`next unless x`、`break unless x` などの早期脱出 | 文の後で非 nil |
| `String.size(x)` など、`x` を引数に取る組み込みの操作 | 呼び出しの後、その操作が受け付ける型（実行時に引数を検査するから） |
| `x in T` / `x => T` / `case x in T` | 一致する型（[制御構造とパターン](06-control.md)） |

```ruby
def find_even(xs) = Array.find(xs) { |x| x % 2 == 0 }
x = find_even(Any[1, 4])
if x
  p(x + 1)                     # => 5
end
p(x + 1) if x != nil           # => 5
def twice(xs)
  x = find_even(xs)
  return 0 unless x
  x * 2
end
p(twice(Any[1, 4]))          # => 8
p(twice(Any[1, 3]))          # => 0
```

フィールドの読み出し（`Node.next(n)`、クラスの関数の中では `@next`）も、ローカル変数から読むものは絞られます。ただし、確かめてから使うまでの間にフィールドを書き換えうる操作があると、絞り込みはそこで切れます。フィールドは可変で、別の名前から書き換えられうるからです。書き換えうる操作は、フィールドへの書き込み、ユーザ関数の呼び出し、ブロックを渡す呼び出しと `yield`、その変数への代入です。ブロックの中では、外で絞ったフィールドは絞られていません。

```ruby error
class Node
  attr_accessor value, :next
end
def mk(v) = Node.new(v, nil)
def drop_next(n) = Node.set_next(n, nil)
a = mk(1)
Node.set_next(a, mk(2))
if Node.next(a)
  p(Node.value(Node.next(a)))  # 絞られている
  drop_next(a)
  p(Node.value(Node.next(a)))  # !> Node.value: argument 1 may be nil (nil | Node) [nil]
end
```

間に呼び出しを挟むなら、フィールドをローカル変数に写してから検査してください。

```ruby
class Node
  attr_accessor value, :next
end
def mk(v) = Node.new(v, nil)
a = mk(1)
Node.set_next(a, mk(2))
nx = Node.next(a)
if nx
  p(Node.value(nx))            # => 2
end
```

### `--strict`

レベル 2 は、検査されていない `nil` を受けうるすべての操作を実行前に報告します。レベル 3 は `x[k]` の結果も対象にします（[概要と実行](01-overview.md)）。

## Ruby の他の型

Ruby の他の型は、Ruby と同じ値を同じ字面で作ります。違いは、操作を型付きで呼ぶことと、グローバル変数（`$1`、`$stdout`）が無いことです。

### Range

反復する操作には Integer か String で始まる Range が要ります。`"A".."Z"` は Ruby と同じく `String#succ` で進みます。`step`、`sum`、`size` は Integer が要ります。別の型の Range（`1.0..2.0`）は `type` で報告されます。

```ruby
p(Range.to_a("a".."e"))        # => ["a", "b", "c", "d", "e"]
p(Range.sum(1..4))             # => 10
p((1..3) == (1..3))            # => true
p(/a/i == /a/i)                # => true
```

```ruby error
Range.each(1.0..2.0) { |x| p(x) }   # !> Range.each: the Range's first value must be Integer|String, but is Float [type]
```

- **等価。** 2 つの Range は端と `exclude_end?` が同じなら `==`、2 つの Regexp はソースとオプションが同じなら `==` です。
- **終端の無い Range。** 有限の Range が要る操作は、終端の無い Range に `RangeError` を投げます。

```ruby error
p(Range.to_a(1..))             # !> RangeError: Range.to_a: cannot do this on an endless Range 1..
```

### Regexp と MatchData

`$1` や `$~` のようなグローバルはありません。MatchData を変数に置いて添字で読みます（`m[1]`）。`String.match` は一致しないと nil を返すので、先に検査します。`String.sub`、`gsub`、`index`、`split` は Regexp も取ります。`/.../n` は Ruby と同じくバイト列の正規表現です。

```ruby
m = String.match("2026-10", /(\d+)-(\d+)/)
if m
  p(m[1])                      # => "2026"
  p(m[2])                      # => "10"
end
p(String.sub("a-b", /-/, "+")) # => "a+b"
p(String.scan("a1b22", /\d+/)) # => ["1", "22"]
```

```ruby error
m = String.match("a1", /(\d)/)
puts($1)                       # !> Sake has no global variables (`$1`)
```

### Time

ゾーンは Ruby と同じ固定の UTC オフセットです: `"+09:00"`、`"-0500"`、`"Z"`、`"UTC"`、軍用の 1 文字、秒数（`3600`）。`Time.new`、`Time.at`、`Time.now` はキーワード `in:` でも取ります。`Time.utc(t)` と `Time.localtime(t, zone)` は変換した複製を返します（Ruby の `utc` と `localtime` はレシーバを変える）。

```ruby
t = Time.new(2026, 10, 1, 9, 0, 0, in: "+09:00")
p(t)                           # => 2026-10-01 09:00:00 +0900
p(Time.utc(t))                 # => 2026-10-01 00:00:00 UTC
p(t)                           # => 2026-10-01 09:00:00 +0900
p(Time.at(0, in: 3600))        # => 1970-01-01 01:00:00 +0100
```

### IO

`IO.stdin`、`IO.stdout`、`IO.stderr` がプログラムのストリームを型 `IO` の値として与えます。Sake に `$stdout` や `STDOUT` は無く、`ARGV` と同じく値は操作から来ます。`File.open(path, mode = "r")` も `IO` を返し、ブロック付きならブロックの値を返してファイルを閉じます。

- **1 つの型。** ファイルとストリームの型は 1 つなので、1 つの関数がどちらにも書けます。
- **パターンと等価。** `IO` はパターンに書け（`in IO`）、同じストリームやファイルの 2 つの IO 値は `==` です。

```ruby
def say(io, s) = IO.puts(io, s)
say(IO.stdout, "to stdout")    # => to stdout
File.open("out.txt", "w") { |f| say(f, "to a file") }
p(File.read("out.txt"))        # => "to a file\n"
p(IO.stdout == IO.stdout)      # => true
```

### エンコーディング

互換でないエンコーディングの文字列が出会うと（`Integer.chr(227)` のバイトと UTF-8 の文章）、rescue できる `EncodingError` が上がります。

```ruby
begin
  s = Integer.chr(227) + "あ"
rescue EncodingError => e
  puts("rescued")              # => rescued
end
```

# 関数とブロック

この章は `def` で定義する関数と、呼び出しに渡すブロックを述べます。どちらにも型は書きません。呼び出し先は実行前に決まるので、引数の数とキーワードの名前は実行前に検査されます。

## 関数

関数は `def` で定義し、引数の数とキーワード名で呼び出しが検査されます。1 行の `def f(x) = 式` と、`end` で閉じる形のどちらも書けます。Ruby のスタイルと同じく、1 行の形は短い式に使い、何段かある本体は `def ... end` に書きます。

```ruby
def area(w, h) = w * h
def describe(n)
  return "negative" if n < 0
  Integer.to_s(n)
end
p(area(3, 4))        # => 12
p(describe(-1))      # => "negative"
p(describe(7))       # => "7"
```

### 位置引数と既定値

必須の位置引数を先に、既定値付きの省略可能な引数をその後に並べます。既定値は Ruby と同じく、呼び出しがその引数を与えなかったときに、前の引数の後で評価されます。前の引数を使えます。

```ruby
def f(a, b = 1, c = b + 1) = [a, b, c]
p(f(10))             # => [10, 1, 2]
p(f(10, 5))          # => [10, 5, 6]
p(f(10, 5, 0))       # => [10, 5, 0]
```

- **数。** 呼び出しは、必須の引数の数から全部の数までの引数を与えます。合わない数は実行前のエラーです。
- **順序。** 引数は書いた順に評価されます。

```ruby error
def area(w, h) = w * h
p(area(3))           # !> wrong number of arguments for area (given 1, expected 2)
```

### キーワード引数

キーワード引数は引数の列の最後に置きます。必須（`w:`）か既定値付き（`h: w`）で、省略可能な位置引数と自由に混ぜられます。

```ruby
def greet(name, greeting = "Hello", punct: "!") = "#{greeting}, #{name}#{punct}"
p(greet("Ruby"))                     # => "Hello, Ruby!"
p(greet("Ruby", punct: "?"))         # => "Hello, Ruby?"
p(greet("Ruby", "Hi", punct: "."))   # => "Hi, Ruby."
punct = "!!"
p(greet("Sake", punct:))             # => "Hello, Sake!!"
```

呼び出し先は実行前に分かるので、検査器は `k: v` を名前で引数に届けます。次はどれも実行前のエラーです。

- 未知のキーワード、同じキーワードの重複、必須キーワードの欠落。
- キーワード引数の無い関数への `k: v`。暗黙の Hash 引数は無いので、Hash が欲しければ `Hash.of(k: v)`、Record が欲しければ `{k: v}` と書きます。

```ruby error
def size(w:, h: w) = w * h
p(size(w: 3, d: 2))  # !> size has no keyword parameter `d`
p(size(h: 3))        # !> size needs keyword argument `w:`
```

- **`f(k:)`** は Ruby と同じく変数 `k` を渡します。
- **組み込み。** いくつかの組み込みも Ruby のキーワードを取り、同じく検査されます: `Time.at(t, in: "+09:00")`、`Dir.glob(pat, base: dir)`。リファレンスでは `[k: T]` と書かれます。

### `*rest`: 残りの位置引数

省略可能な引数の後の `*rest` は、残りの位置引数を新しい Array に集めます。`*rest` を持つ関数は任意個の引数で呼べます。呼び出しの側では `*xs` が Tuple か Array を広げて渡します。

```ruby
def join(sep, *parts) = Array.join(parts, sep)
p(join("-"))                  # => ""
p(join("-", "a", "b", "c"))   # => "a-b-c"
xs = ["x", "y"]
p(join("+", *xs))             # => "x+y"
```

- **要素の型。** `rest` は 1 つの Array なので、要素は 1 つの型です。すべての呼び出しが渡すものの和になります。位置ごとの型を保ちたければ Tuple を 1 つ渡します: `notify("stock", ["AAPL", 120])` と呼び、関数の中で `name, price = event` と分けます。
- **組む場所。** 呼び出し先が分かるので、Array は呼び出しの場で組まれます。
- **順序。** 引数は必須、省略可能、`*rest`、キーワード、`**opts` の順です。`*rest` の後の位置引数と、名前の無い `*` は実行前のエラーです。
- **`*xs` の行き先。** `*xs` は `*rest` と、任意個の引数を取る組み込み（`puts`、`format`、`Any[...]`、`Array.push` など）にだけ渡せます。必須や省略可能な引数を `*xs` で埋めることはできません。

```ruby error
def f(*rest, z) = z   # !> parameters after `*rest` are not supported: required, optional, `*rest`, keywords, `**opts`, in that order
```

### `**opts`: 残りのキーワード

最後の `**opts` は、引数の名前ではないキーワードを Symbol キーの Hash に集めます。これも呼び出しの場で組まれます。

```ruby
def tag(name, **opts) = [name, opts]
p(tag("div"))                            # => ["div", {}]
p(tag("div", id: "main", hidden: true))  # => ["div", {id: "main", hidden: true}]
```

- **綴り間違い。** `**opts` を持つ関数はどのキーワードも受けるので、綴り間違いはそこではエラーになりません。
- **名前の無い `**`** は実行前のエラーです。

### キーワードを渡し直す: `g(**opts)`

`g(**opts)` は、集めたキーワードを `def` で定義した関数 `g` にそのまま渡します（Ruby と同じ）。各キーは `g` の同じ名前のキーワードに入り、残りは `g` 自身の `**` に入ります。

```ruby
def parse(s, sep: ",", upcase: false)
  fields = String.split(s, sep)
  upcase ? Array.map(fields) { String.upcase(_1) } : fields
end
def read(s, **opts) = parse(s, **opts)
p(read("a;b", sep: ";"))                # => ["a", "b"]
p(read("a;b", sep: ";", upcase: true))  # => ["A", "B"]
```

- **キーごとに型を保つ。** 検査器はキーワードを集めた呼び出しから各キーを追うので、ここで `sep` は String、`upcase` は Boolean で、両者の union にはなりません。
- **渡せるのは関数自身の `**` 引数だけ**です。任意の Hash は渡せません。
- **書いたキーワードと同じく検査します。** `g` に無いキーや、足りない必須キーワードは実行前のエラーです（実行時なら Ruby と同じ `ArgumentError`）。
- **並べて書いたキーワード。** `**opts` より前に書いたものは opts が上書きする既定値（`parse(s, sep: ";", **opts)`）、後に書いたものは opts を上書きします。
- **先に opts を変えると。** opts に書き込むと（`Hash.delete(opts, :k)`、`opts[k] = v`）、キーを 1 つずつは追わなくなります。各キーワードは値全体の union になり、`g` に無いキーが入りうるとみなします。

```ruby error
def parse(s, sep: ",") = String.split(s, sep)
def read(s, **opts) = parse(s, **opts)
p(read("a;b", sepp: ";"))
```

最後の行は `**opts` の場所で報告されます: `parse: the keywords passed on with ** hold :sepp, which parse has no keyword parameter for`、ヒントは `did you mean sep:?`。

### ブロック引数 `&b`

`&b`（または `&` だけ）は、関数が受けたブロックを別の呼び出しに渡すためだけの引数です。「ブロック」の節で述べます。

### mixin 関数の定義の一致

module の mixin 関数は第 1 引数の型の定義にディスパッチします（[プログラムの構造と名前解決](02-program.md)）。そのため、各型の定義は引数の数、キーワードの名前、`*rest` / `**opts` の有無が一致しなければなりません。一致しなければ呼び出しの場で実行前のエラーです。

```ruby error
module Shape
  def area(s) = raise NotImplementedError
end
class Sq
  include Shape
  attr_reader side
  def area(s) = @side * @side
end
class Rect
  include Shape
  attr_reader w, h
  def area(r, scale) = @w * @h * scale
end
p(Shape.area(Sq.new(2)))   # !> Shape.area dispatches to Rect.area, whose arguments or block differ from Shape.area
```

### 返り値

関数の値は最後の式の値か、`return expr` の値です。`return a, b` は Tuple `[a, b]` を返すので、呼び出し側で `a, b = f(...)` と受けられます。

```ruby
def minmax(xs) = return Array.min(xs), Array.max(xs)
lo, hi = minmax(Any[3, 1, 2])
p([lo, hi])          # => [1, 3]
```

### 多相

関数は多相です。型を書かないので、その中の操作が受け付けるどんな引数でも動きます。型エラーは、失敗した操作の行で表面化します。検査器はその行を報告し、どの呼び出しからそこに届いたかをヒントに出します。

```ruby
def twice(x) = x + x
p(twice(2))          # => 4
p(twice("ab"))       # => "abab"
p(twice(1.5))        # => 3.0
```

```ruby error
def twice(x) = x + x   # !> Arithmetic.+: the operands are (:a, :a), which the left operand's type does not support
p(twice(:a))
```

### ローカル変数

各関数は自分のスコープを持ちます。トップレベルのローカル変数には触れません。

```ruby error
count = 10
def bump = count + 1   # !> undefined local variable or function `count`
```

Ruby と同じく、代入が字面上は前にあって、まだ実行されていないローカルを読むと `nil` です。

```ruby
def f
  x = 1 if false
  p(x)               # => nil
end
f
```

### 再帰

再帰は可能です。深さが 10,000 を超えると `SystemStackError` になります。`bin/sake` は大きなスタックのスレッドでプログラムを走らせるので、Ruby のスタックではなくこの上限が効きます。長いバックトレースは途中が省略されます。

```ruby
def fact(n) = n <= 1 ? 1 : n * fact(n - 1)
p(fact(20))          # => 2432902008176640000
def down(n) = n == 0 ? 0 : down(n - 1)
p(down(9_000))       # => 0
```

```ruby error
def down(n) = n == 0 ? 0 : down(n - 1)
p(down(20_000))      # !> SystemStackError: stack level too deep
```

## ブロック

ブロックは、組み込みの操作か、`yield` するユーザ関数に渡します。繰り返しの多くは `Array.each` などのブロックを取る操作で書きます。

```ruby
xs = Any[1, 2, 3]
p(Array.map(xs) { |x| x * 2 })      # => [2, 4, 6]
Hash.each(Hash.of(a: 1, b: 2)) do |k, v|
  puts "#{k}=#{v}"                  # => a=1
                                    # => b=2
end
Integer.times(3) { p it }           # => 0
                                    # => 1
                                    # => 2
```

### 値ではない

ブロックは第二級です。変数に格納することも、関数から返すこともできません。`proc`、`lambda`、`->` はありません。

```ruby error
f = proc { |x| x }   # !> undefined function `proc`
```

### 引数

`|a, b|` に名前を並べます。`it` と `_1` … `_9` は Ruby と同じです。

```ruby
p(Array.map(Any[1, 2]) { _1 * 10 })   # => [10, 20]
p(Array.map(Any[1, 2]) { it + 1 })    # => [2, 3]
```

### 分解

ブロックが 2 つ以上の引数を宣言し、1 つの Tuple か Array を受けると、その要素が引数になります。足りないものは nil、余りは捨てます。Ruby と同じです。引数自身も `( )` で分解できます。

```ruby
pairs = Any[["a", 1], ["b", 2]]
Array.each(pairs) { |name, n| p("#{name}=#{n}") }              # => "a=1"
                                                               # => "b=2"
Array.each_with_index(pairs) { |(name, n), i| p([i, name]) }   # => [0, "a"]
                                                               # => [1, "b"]
p(Array.inject(pairs, 0) { |acc, (k, v)| acc + v })            # => 3
Array.each(Any[[1, 2]]) { |a, b, c| p([a, b, c]) }           # => [1, 2, nil]
```

### rest 引数

`|a, *rest|`（`|a, *rest, z|`、`|*all|` も）は残りの引数、または分解した Tuple / Array の残りの要素を新しい Array に集めます。`a, *rest = x` と同じです。`|*all|` だけでは分解しません。

```ruby
Array.each(Any[[1, 2, 3]]) { |a, *rest| p([a, rest]) }      # => [1, [2, 3]]
Array.each(Any[[1, 2, 3]]) { |a, *rest, z| p([a, rest, z]) } # => [1, [2], 3]
Array.each(Any[[1, 2, 3]]) { |*all| p(all) }                # => [[1, 2, 3]]
```

### 引数の数

引数の無いブロックは渡された引数を無視します。それ以外で引数の数が合わないブロック呼び出しは、実行時の `ArgumentError` です。rest 引数があれば、他の引数より少ないときだけです。

```ruby
Integer.times(2) { puts "hi" }      # => hi
                                    # => hi
```

```ruby error
Array.each_with_index(Any["a"]) { |x| p(x) }   # !> ArgumentError: block takes 1 parameter(s) but was given 2
```

### スコープ

ブロックは囲むローカル変数を読み書きできます。

```ruby
sum = 0
Array.each(Any[1, 2, 3]) { |x| sum += x }
p(sum)               # => 6
```

### `yield` と省略可能なブロック

`yield(args...)` は今の関数に渡されたブロックを呼びます。関数の外の `yield` は構文エラーです。`yield` を含む関数は、呼び出しごとにブロックを受けなければなりません。

```ruby error
def each_twice(xs)
  Array.each(xs) { |x| yield x; yield x }
end
each_twice(Any[1, 2])   # !> each_twice uses `yield` but no block is given
```

`block_given?` は今の関数がブロックを受けたかを言います。それを検査する関数はブロック無しで呼べます。

```ruby
def info(msg = nil) = puts(block_given? ? yield : msg)
info("plain")                 # => plain
info { "from block" }         # => from block
```

- **分岐の解析。** 検査器は呼び出しごとにブロックの有無を知っているので、取られる分岐だけを解析します。`&&`、`||`、`!` の中の `block_given?` も同じです。
- **届かないはずの `yield`。** ブロック無しで届く `yield`（またはブロックが要る呼び出しへの `&b`）は `type` レベルのエラーです。実行時は `LocalJumpError` で、rescue はできません。

### ブロックを渡す: `&b`

`def f(xs, &b) = Array.map(xs, &b)` は自分のブロックを別の呼び出しに渡します。`&` だけでも書けます。`b` は `&b` としてしか使えません。

```ruby
def twice(xs, &b) = Array.map(xs, &b)
p(twice(Any[1, 2]) { |x| x * 2 })      # => [2, 4]
def each_pair(h, &) = Hash.each(h, &)
each_pair(Hash.of(a: 1)) { |k, v| p([k, v]) }   # => [:a, 1]
```

- **ブロック無しの呼び出し。** Ruby と同じく、ブロックを渡すだけの関数はブロック無しで呼べます。その先のブロックが要る呼び出しに何も届かなければ、`type` レベルのエラーです。
- **`break`。** 渡されたブロックの中の `break` は、ブロックが書かれた呼び出し（上の `twice(...)`）を終えます。

```ruby error
def twice(xs, &b) = Array.map(xs, &b)   # !> the block passed on is missing here, and this call needs one
p(twice(Any[1, 2]))
```

### `next`・`break`・`return`

Ruby と同じ 3 つの抜け方があります。

| 書き方 | 終えるもの | 値 |
|---|---|---|
| `next [v]` | 今のブロック呼び出し | `v`（既定 `nil`）がブロックの値 |
| `break [v]` | ブロックを渡した呼び出し | `v`（既定 `nil`）がその呼び出しの値 |
| `return [v]` | 囲む**関数** | `v` が関数の値 |

```ruby
xs = Any[1, 2, 3, 4]
p(Array.map(xs) { |x| next 0 if x % 2 == 0; x })   # => [1, 0, 3, 0]
p(Array.each(xs) { |x| break x if x > 2 })          # => 3
p(Array.each(xs) { |x| x })                         # => [1, 2, 3, 4]
def first_big(xs)
  Array.each(xs) { |x| return x if x > 2 }
  nil
end
p(first_big(xs))                                    # => 3
```

- **`while` の中。** ブロックの中の `while` の中では、`break` は `while` を抜けます。
- **型。** 検査器は `break` の値を呼び出しの結果型に加えます。

> [!NOTE]
> ブロックの引数とローカルは、囲む関数のフレームに属します。ブロックを**スレッドで後から**走らせる関数（concurrent-ruby 風の `post { ... }`）に渡すと、スレッドが走る時点の値（ループ変数の最後の値）を読みます。Ruby ではブロック引数は呼び出しごとに新しい値です。スレッドを使わない限り違いは観測できません（`TODO.md`）。

## once

`once { ... }` はブロックの値を与えます。ブロックはプログラムのその場所に最初に到達したときに走り、その後そこを通るたびに、プログラム全体・すべてのスレッドで同じ値を返します。値の定数が無い Sake で、表や名前付きの値を 1 度だけ計算する方法です。

```ruby
def table = once { puts "computing"; Array.map(Any[1, 2, 3]) { |i| i * i } }
p(table)             # => computing
                     # => [1, 4, 9]
p(table)             # => [1, 4, 9]
Array.push(table, 16)
p(table)             # => [1, 4, 9, 16]
```

- **共有。** 値は Ruby の定数と同じく共有されます。上のように、`once` が保持する Array は変えられます。
- **再入。** 計算中に自分の `once` に再び到達するブロックはプログラムの誤りで、`SystemStackError` です。
- **型。** 実行前の検査では、その型はそれを計算しうるすべての呼び出しでのブロックの結果の和です。

```ruby error
def loop_once = once { loop_once }
p(loop_once)         # !> SystemStackError: once: the block reached its own once again while computing it
```

# 演算子と添字

この章は `a + b` のような二項演算子と、`x[k]` の添字を述べます。どちらも module の関数の略記で、左のオペランド（レシーバ）の型で解決されます。自分のクラスに演算子や添字を与えるには、その module を include して関数を定義します。

## 二項演算子

各演算子は module に属し、`a OP b` はその module の関数を呼ぶ略記です: `a + b` は `Arithmetic.+(a, b)` です。module の関数は第 1 引数の型で解決されるので（[module の関数の呼び方](02-program.md)）、この呼び出しは `a` の型 `T` の `T.+(a, b)` を走らせます。つまり演算子は**左のオペランド**でディスパッチします。エラーの文は module の関数の名で出ます（`Arithmetic.*: ...`）。

```ruby
p(1 + 2)                  # => 3
p(Arithmetic.+(1, 2))     # => 3
p(Integer.+(1, 2))        # => 3
p("a" + "b")              # => "ab"
```

| module | 演算子 | include する組み込み型 |
|---|---|---|
| `Arithmetic` | `+ - * / % **`、単項 `-x` `+x`（`-@` `+@`） | Integer, Float, Rational, Complex, String, Time, Set |
| `Comparable` | `<=> < <= > >=` | Integer, Float, Rational, String, Time, Tuple, Array |
| `Bitwise` | `& \| ^ << >>`、単項 `~x` | Integer, Set |
| `Indexable` | `[]`, `[]=`（下記「添字」） | Array, Hash, String, Tuple, MatchData |
| `Kernel` | `== != =~ !~` | すべての型 |

### 明示の形

`Arithmetic.+(a, b)` は `a + b` と同じようにディスパッチします。`Integer.+(a, b)` は Integer の `+` を直接呼びます。`a` は Integer でなければならず、`b` は Integer の `+` が受けるどの型でもよい。

```ruby error
p(Integer.+("a", "b"))    # !> Integer.+: argument 1 must be Integer, but is String
```

### 自分の型に演算子を与える

クラスは module を include し、本体に演算子を定義すると演算子に参加します。`include Arithmetic` と `def +(a, b)` などです。`include Comparable` では `<=>` を定義すれば十分で、`<`、`<=`、`>`、`>=` はそこから来ます。`Array.sort`、`min`、`max` もその `<=>` を使います。

```ruby
class Money
  include Arithmetic
  include Comparable
  attr_reader cents
  def +(a, b) = Money.new(@cents + Money.cents(b))
  def <=>(a, b) = @cents <=> Money.cents(b)
  def to_s(m) = format("$%d.%02d", @cents / 100, @cents % 100)
end
a = Money.new(150)
b = Money.new(250)
puts(a + b)                                        # => $4.00
p(a < b)                                           # => true
puts(Array.join(Array.sort(Any[b, a]), " "))     # => $1.50 $2.50
```

左のオペランドの型が、その演算子の module を include していない、または演算子を定義していないときは、実行前に `type` の問題、実行時は `TypeError` です。

```ruby error
Point = Struct.new(:x, :y)
p(Point.new(1, 2) + Point.new(1, 2))   # !> Arithmetic.+: Point does not include Arithmetic
```

### 左が組み込み型のとき: coerce

`2 + money` は Integer でディスパッチしますが、Integer の表に Money の行はありません。クラスが Ruby のプロトコルと同じく Tuple `[left, right]` を返す `coerce(b, a)` を定義していれば、組を先に変換してから演算子を走らせます。下の `coerce` で `2 + money` は `Money.new(200) + money` になります。検査器も変換を追います。

```ruby
class Money
  include Arithmetic
  attr_reader cents
  def +(a, b) = Money.new(@cents + Money.cents(b))
  def coerce(m, other) = [Money.new(other * 100), m]
end
m = Money.new(50)
p(2 + m)                  # => #<struct Money cents=250>
```

### 等価

クラスの値の `==` は、型が自分の `==` を定義していなければ、Ruby の Struct と同じく型とフィールドを比べます。`Array.include?`、`index` などは同じ等価を使います。

```ruby
Point = Struct.new(:x, :y)
p(Point.new(1, 2) == Point.new(1, 2))   # => true
p(Point.new(1, 2) == Point.new(2, 1))   # => false
p(Point.new(1, 2) == "x")               # => false
p(Array.include?(Any[Point.new(1, 2)], Point.new(1, 2)))   # => true
```

`Comparable` を include して `<=>` を定義した（`==` は定義しない）型は、Ruby の `Comparable#==` と同じく、同じ型の値と `<=>` が 0 のとき等しい。別の型の値（nil など）とは決して等しくなく、そのとき `<=>` は呼ばれません。上の Money では `a == Money.new(150)` が true、`a == nil` が false です。

### 組み込み型の表

組み込み型では、結果の型は両オペランドの型から**閉じた表**で決まります。

| 演算子 | 行 |
|---|---|
| `+` | (Integer, Integer) → Integer。Float を含めば Float。Rational を含み Float を含まなければ Rational。Complex を含めば Complex。(String, String) → String |
| `-` `*` `/` `%` `**` | 数値の組は `+` と同じ |
| `*` | (String, Integer) → String も |
| `<` `<=` `>` `>=` `<=>` | 数値の組、(String, String)、(Tuple, Tuple)、(Array, Array) → true/false（`<=>` は -1, 0, 1, nil） |
| `==` `!=` | **任意の 2 値**: 同じ型の等しい値（数は Integer・Float・Rational をまたいで比べる）。Ruby と同じく、別の型の値は等しくない |
| `+` `-` | (Array, Array) → Array（連結。差） |
| `*` | (Array, Integer) → Array（繰り返し） |
| `<` `<=` `>` `>=` `<=>` | (Symbol, Symbol) も |
| 単項 `-` `+` | Integer, Float, Rational, Complex → 同じ型 |
| 単項 `~` | Integer → Integer |
| `&` `\|` `^` `<<` `>>` | (Integer, Integer) → Integer |
| `\|` `&` `-` | (Set, Set) → Set（和、積、差） |
| `=~` | (String, Regexp), (Regexp, String) → Integer か nil。`!~` (String, Regexp) → true/false |
| `%` | (String, Integer / Float / String / Symbol / Tuple / nil / true / false) → String、Ruby の format（`"%d items" % 3`、`"%s-%s" % [a, b]`） |

```ruby
p("ab" * 3)                    # => "ababab"
p(Any[1, 2] + Any[3])      # => [1, 2, 3]
p(Any[1, 2, 3] - Any[2])   # => [1, 3]
p(Set.of(1, 2) | Set.of(2, 3))       # => Set[1, 2, 3]
p(5 & 3)                       # => 1
p(1 << 4)                      # => 16
p("abc" =~ /b/)                # => 1
p("abc" !~ /z/)                # => true
p("%s-%s" % ["a", "b"])        # => "a-b"
```

### 合う行が無いとき

オペランドの型に合う行が無ければ、実行前は `type` の問題、実行時は `TypeError` です。実行時のメッセージは存在する行を列挙します。暗黙の変換はありません。

```ruby error
p("a" - "b")   # !> Arithmetic.-: the operands are (String, String), which the left operand's type does not support
```

### 数値

Integer の `/` と `%` は Ruby に従い、負の数では床に向かって丸めます。Integer のゼロ除算は `ZeroDivisionError`、Float のゼロ除算は IEEE に従います。

```ruby
p(7 / 2)        # => 3
p(-7 / 2)       # => -4
p(-7 % 2)       # => 1
p(7.0 / 2)      # => 3.5
p(1 / 2r)       # => (1/2)
p(1.0 / 0)      # => Infinity
```

- **負の指数。** `Integer ** 負の Integer` は `ArgumentError` です。`a ** b` の型が `b` の値に依らないためです。Rational が欲しければ `2r ** -1` と書きます（`(1/2)`）。
- **Complex。** 順序が無いので `<` などは定義されません。

```ruby error
p(1 / 0)        # !> ZeroDivisionError: Arithmetic./: divided by 0
```

```ruby error
p(2 ** -1)      # !> ArgumentError: Arithmetic.**: Integer ** negative Integer (2 ** -1) is an error; for a Rational, write 2r ** -1
```

### Time

`Time ± 数` は Time、`Time - Time` は秒の Float です。2 つの Time は比較できます。

```ruby
t = Time.at(0, in: "+00:00")
p(t + 60)                 # => 1970-01-01 00:01:00 +0000
p(Time.at(60) - t)        # => 60.0
p(t < Time.at(1))         # => true
```

### 等しさと順序の規則

別の型の値は決して等しくありません。`1 == :a` と `struct == "x"` は Ruby と同じく false です。クラス自身の `==` があればそれが決めます。数だけは Integer・Float・Rational をまたいで比べます。

```ruby
p(1 == 1.0)     # => true
p(1 == 1r)      # => true
p(1 == :a)      # => false
p("1" == 1)     # => false
```

Tuple、Array、Set、Hash、Record は中身が等しいとき等しい。2 つの Record は同じフィールドも要ります。Tuple と Array は Ruby の Array と同じく要素ごとに順序付けられます。

```ruby
p([1, 2] == [1, 2])                 # => true
p([1, 2] == Any[1, 2])            # => false
p({x: 1} == {x: 1, y: 2})           # => false
p(Set.of(1, 2) == Set.of(2, 1))           # => true
p([1, 2] < [1, 3])                  # => true
p(Any[1, 2] <=> Any[1, 2, 0])   # => -1
```

比べられない要素があれば、`<` などは `ArgumentError`、`<=>` は nil です。検査器は、比べられない要素型を実行前に報告します。

```ruby error
p(Any["a", 1] < Any["a", "b"])   # !> Comparable.<: elements compared in order may be (Integer, String), which cannot be compared
```

### 演算子ではないもの

- **`!x`** は `x ? false : true` です。どの値にも使え、型の操作ではありません。
- **複合代入。** `x OP= e` は `x = x OP e` です。
- **`&&` と `||`** は Ruby と同じく短絡し、オペランドの一方を返します。

```ruby
p(!0)                  # => false
p(!nil)                # => true
x = 5
x += 2
p(x)                   # => 7
p(nil || "default")    # => "default"
p(1 && "second")       # => "second"
```

## 添字

`x[k]` は `Indexable.[](x, k)`、`x[k] = v` は `Indexable.[]=(x, k, v)` で、`x` の型の `[]` と `[]=` を走らせます。

```ruby
xs = Any[10, 20, 30]
p(xs[0])                  # => 10
p(xs[-1])                 # => 30
p(xs[1..])                # => [20, 30]
p(xs[0, 2])               # => [10, 20]
p(Indexable.[](xs, 1))    # => 20
xs[1] = 25
p(xs)                     # => [10, 25, 30]
```

組み込み型は次のとおりです。

| レシーバ, 添字 | `x[k]` | `x[k] = v` |
|---|---|---|
| Array, Integer | 要素。Array の外なら nil | `v` を格納（T の Array は `v` を検査） |
| String, Integer | 1 文字の String。外なら nil | 不可 |
| Tuple, Integer | 要素。Tuple の外は `IndexError` | その位置の型なら `v` を格納 |
| Array, Range / String, Range | スライス、または nil | 不可 |
| Array, Integer, Integer / String, Integer, Integer（`s[start, length]`） | スライス、または nil | 不可 |
| Hash, 任意のキー | 値、または既定値（`Hash.new(default)` で作っていなければ nil） | `v` を格納 |
| MatchData, Integer / String | グループ、または nil | 不可 |

```ruby
s = "hello"
p(s[0])                   # => "h"
p(s[1..2])                # => "el"
p(s[1, 3])                # => "ell"
h = Hash.of("a" => 1)
p(h["a"])                 # => 1
p(h["z"])                 # => nil
p(Hash.new(0)["z"])       # => 0
m = String.match("2026-10", /(\d+)-(\d+)/)
if m
  p(m[0])                 # => "2026-10"
  p(m[2])                 # => "10"
end
```

### 外れた添字

負の添字は Ruby と同じく末尾から数えます。外れた添字の値は Ruby と同じく `nil` なので、`a[i]` の静的な型は `T | nil` です。結果を検査せずに使うと、レベル 3 の `index-nil` が報告します。レベル 2 は通し、実行時にその操作で止まります。`Array.fetch(a, i)` は代わりに `IndexError` を投げます。

```ruby error
xs = Any[10, 20, 30]
p(xs[5] + 1)              # !> TypeError: Arithmetic.+: no implementation for (nil, Integer)
```

```ruby error
xs = Any[10, 20, 30]
p(Array.fetch(xs, 5))     # !> IndexError: Array.fetch: index 5 outside of array bounds: -3...3
```

Tuple は長さが型の一部なので、外の添字は `IndexError` です。添字が定数なら実行前に報告されます。

```ruby error
t = [1, "a"]
p(t[2])                   # !> Indexable.[]: the index is outside the Tuple [Integer, String]
```

### 書き込み

型無しの Array の末尾の先に書くと、Ruby と同じく隙間が nil で埋まります。T の Array は nil が T でないので `IndexError` です。T でない値の書き込みは実行前に `type` の問題です。Tuple への書き込みは、その位置の型の値だけです。String には書けません。

```ruby
xs = Any[1]
xs[3] = 4
p(xs)                     # => [1, nil, nil, 4]
```

```ruby error
ys = Integer[1]
ys[3] = 4                 # !> IndexError: Array.[]=: index 3 is past the end of Integer[] (length 1); the gap would be nil
```

```ruby error
ys = Integer[1]
ys[0] = "a"               # !> Indexable.[]=: an element must be Integer, but is String
```

### 複合代入

`x[k] OP= v` と `x[k] ||= v` は `x` と `k` を 1 度だけ評価します。ローカル変数の `y ||= v` は、`y` が nil か false のときだけ代入します。

```ruby
h = Hash.new
h[:a] ||= Any[]
Array.push(h[:a], 1)
h[:a] ||= Any[]
p(h)                      # => {a: [1]}
y = nil
y ||= 5
y ||= 6
p(y)                      # => 5
```

### 自分の型に添字を与える

クラスは `include Indexable` と `def [](x, k)` / `def []=(x, k, v)` で参加します。添字が 2 つなら `m[r, c]` は `def [](m, r, c)`、`m[r, c] = v` は `def []=(m, r, c, v)` を呼びます。

```ruby
class Grid
  include Indexable
  attr_reader w, cells
  def [](g, r, c) = @cells[r * @w + c]
  def []=(g, r, c, v)
    @cells[r * @w + c] = v
  end
end
g = Grid.new(2, Any[0, 0, 0, 0])
g[1, 0] = 7
p(g[1, 0])                # => 7
p(Grid.cells(g))          # => [0, 0, 7, 0]
```

# 制御構造とパターン

Sake の制御構造は Ruby のものです。`if` と `while`、修飾子の形、早期 `return`、そして `case` を Ruby と同じ字面で書きます。違いは 3 つあります。反復は `for` ではなく `Array.each` のようなブロックを取る操作で書きます。`case` は `when` ではなく `in` のパターンで分岐します。そして、条件は値を調べるだけでなく、検査器が追う変数の**型を絞り**ます。nil かもしれない値や `Integer | String` のような和を使うには、この絞り込みを使います。

この章の例の `# => 値` は `bin/sake --strict=2` の実際の出力です。

## 条件分岐

`if` / `elsif` / `else`、`unless` / `else`、三項演算子 `c ? a : b` は Ruby と同じです。どれも式で、取った分岐の値を返します。取る分岐が無ければ値は `nil` です。

```ruby
n = 5
r = if n > 10 then "big" elsif n > 3 then "mid" else "small" end
p(r)                                 # => "mid"
p(if n > 10 then "big" end)          # => nil
p(unless n > 10 then "not big" end)  # => "not big"
p(n > 3 ? "yes" : "no")              # => "yes"
```

### 真偽

偽は `nil` と `false` だけです。`0`、`""`、空の Array を含む他のすべての値は真です。`&&`、`||`、`!` は Ruby と同じで、`&&` と `||` は最後に評価したオペランドを返します。

```ruby
p(0 ? "truthy" : "falsy")            # => "truthy"
p("" ? "truthy" : "falsy")           # => "truthy"
p(nil ? "truthy" : "falsy")          # => "falsy"
p(nil || "default")                  # => "default"
p(0 && "zero is truthy")             # => "zero is truthy"
```

### 修飾子の形

文の後ろに条件を置く `stmt if c`、`stmt unless c`、`stmt while c`、`stmt until c` が書けます。

```ruby
n = 5
puts("positive") if n > 0            # => positive
i = 0
i += 1 while i < 3
p(i)                                 # => 3
i -= 1 until i == 0
p(i)                                 # => 0
```

## ループ

`while` と `until` は Ruby と同じです。ループの中で `break` はループを抜け、`next` は次の反復に進みます。ループの値は `nil` で、`break v` で抜けたときだけ `v` です。

```ruby
i = 0
out = Any[]
r = while i < 10
  i += 1
  next if i % 2 == 0
  break if i > 7
  Array.push(out, i)
end
p(out)                               # => [1, 3, 5, 7]
p(r)                                 # => nil
```

### 反復はブロックを取る操作で書く

`for` は未対応です。列を回すときは、`Array.each`、`Integer.times`、`Range.each` のようなブロックを取る操作に書きます（[関数とブロック](04-functions.md)）。ブロックの中の `break v` は、そのブロックを渡した呼び出しを値 `v` で終えます。`next v` はそのブロックの 1 回分を `v` で終えます。

```ruby
xs = Any[3, 8, 12, 5]
big = Array.each(xs) { |x| break x if x > 10 }
p(big)                               # => 12
squares = Any[]
Integer.times(4) { |i| next if i == 0; Array.push(squares, i * i) }
p(squares)                           # => [1, 4, 9]
```

`loop { ... }` は `break` まで繰り返し、`break` の値がその値です。

```ruby
i = 0
r = loop do
  i += 1
  break i * 10 if i == 3
end
p(r)                                 # => 30
```

### 未対応の形

`for` と `begin ... end while` は静的エラーです。

```ruby error
for i in 1..3                        # !> `for` is not supported; iterate with an operation
  p(i)
end
```

## 関数からの早期脱出

`return` は関数をその場で終えます。`return v` の値 `v` が関数の値で、`return a, b` は Tuple `[a, b]` を返します。修飾子の形 `return v if c` が、場合分けの先頭で前提を片付ける書き方です。ブロックの中の `return` も、ブロックではなく外側の**関数**から戻ります（[関数とブロック](04-functions.md)）。

```ruby
def sign(n)
  return "negative" if n < 0
  return "zero" if n == 0
  "positive"
end
p(sign(-2))                          # => "negative"
p(sign(0))                           # => "zero"
p(sign(7))                           # => "positive"
```

## case / in

`case x` に `in P then ...` の分岐を続けると、最初に一致した分岐が走ります。分岐の本体は `then` の後に書いても、次の行に書いてもかまいません。どの分岐も一致せず `else` が無ければ、実行時エラー `NoMatchingPatternError` です。

```ruby
def kind(v)
  case v
  in nil then "nothing"
  in true | false then "bool"
  in Integer | Float then "number"
  in String
    "text"
  end
end
p(kind(nil))                         # => "nothing"
p(kind(true))                        # => "bool"
p(kind(2.5))                         # => "number"
p(kind("s"))                         # => "text"
```

`case`/`when` は未対応です。Ruby の `when` はレシーバの `===` でディスパッチしますが、Sake に `===` は無く、一致は型タグと値の比較です。パターンに書けるものは、この章の最後の節「パターンマッチ」の表のとおりです。

```ruby error
x = 1
case x                               # !> `case`/`when` is not supported (Ruby's `===` dispatches on the receiver); match with `case x` / `in Type`
when 1 then puts("one")
end
```

## 条件による絞り込み

検査器はローカル変数の型をプログラム全体で推論します。条件は、取った分岐の中でその変数の型を**絞り**ます。`if x` の中で `x` は nil ではなく、`if x in Integer` の中で `x` は Integer です。nil かもしれない値（`nil | String`）や和（`Integer | String`）を、`type` や `nil` の報告なしに使う方法がこれです。

### nil を外す

ローカル変数 `x` は次の場所で絞られます（[値と型](03-values.md)の nil の節と同じ表です）。

| 形 | `x` が絞られる場所 |
|---|---|
| `if x` / `while x` / `x && …` | `x` が真のときに取る分岐で非 nil |
| `x != nil` / `x == nil` | 対応する分岐で nil または非 nil |
| `!x` / `unless x` | 同じで、分岐が入れ替わる（`if !x … else` の else で非 nil） |
| `return unless x`、`next unless x`、`break unless x`、その他の早期脱出 | その文の後で非 nil |
| `String.size(x)` など、`x` を引数に取る組み込み操作 | 呼び出しの後で、その操作が受け付ける型（操作は走るときに引数を検査する） |

```ruby
def greet(name = nil)
  if name
    "Hello, " + String.upcase(name)
  else
    "Hello"
  end
end
p(greet("ko1"))                      # => "Hello, KO1"
p(greet())                           # => "Hello"
```

`if name` を外すと、`greet()` の呼び出しについて検査器が報告します。検査器は関数を呼び出しごとに解析するので、報告には至った呼び出しの行が付きます。

```ruby error
def greet(name = nil)
  String.upcase(name)                # !> String.upcase: argument 1 must be String, but is nil [type]
end
p(greet("ko1"))
p(greet())
```

早期脱出で外す形もよく使います。`while x` も同じ絞り込みです。

```ruby
def size_or_zero(xs)
  x = Array.first(xs)
  return 0 unless x
  String.size(x)
end
p(size_or_zero(Any["abc"]))        # => 3
p(size_or_zero(Any[]))             # => 0
```

### フィールドの絞り込みが切れるとき

ローカル変数から読むフィールド（`Node.next(n)`、`@next`）も、`if Node.next(n)` の中では非 nil に絞られます。ただしフィールドは可変なので、確かめてから使うまでの間に、フィールドを書き換えうる操作があると絞り込みが切れます。フィールドへの書き込み、ユーザ関数の呼び出し、ブロックを渡す呼び出しと `yield`、その変数への代入です。ブロックの中でも、外で絞ったフィールドは絞られていません。そういう所では、フィールドをいったんローカル変数に写し、そのローカルを調べます。

```ruby
class Node
  attr_accessor value, :next
end
def next_value(n)
  nx = Node.next(n)
  if nx
    Node.value(nx)
  else
    0
  end
end
a = Node.new(1, nil)
b = Node.new(2, a)
p(next_value(b))                     # => 1
p(next_value(a))                     # => 0
```

```ruby error
class Node
  attr_accessor value, :next
end
def bump(n) = Node.set_value(n, Node.value(n) + 1)
def next_value(n)
  if Node.next(n)
    bump(n)
    Node.value(Node.next(n))         # !> Node.value: argument 1 must be Node, but is nil [type]
  else
    0
  end
end
p(next_value(Node.new(1, nil)))
```

### 型で絞る

`x in Integer` は `x` が Integer のとき真で、その分岐の中で `x` は Integer に絞られます。`elsif` と `else` は残りの型を見ます。`case x` の `in` 分岐も同じです。モジュールの名前は、それを include した型のどれかに合います（`in Shape` は `in Circle | Square`）。組み込みの例外型は Ruby の子も含みます（`in IndexError` は KeyError にも合う）。

```ruby
def pick(flag) = flag ? 1 : "one"
def describe(x)
  if x in Integer
    x + 1
  elsif x in String
    String.size(x)
  else
    x
  end
end
p(describe(pick(true)))              # => 2
p(describe(pick(false)))             # => 3
```

### どのレベルで報告されるか

nil かもしれない値を検査せずに操作に渡すと、レベル 2（`--strict`）で `nil` 項目として報告されます。ただし、要素が無いときの nil（`x[k]`、`Array.first`、`Hash.dig` など）はレベル 3 の `index-nil` 項目です。レベルと項目は[概要と実行](01-overview.md)にあります。報告されなかった nil も、受け取った操作が実行時に `TypeError` で止めます。

## パターンマッチ

`x in P` は `x` がパターン `P` に一致するとき真です。`x => P` はそれを主張します。一致しなければ `NoMatchingPatternError` を投げ、Record パターンのフィールドを束縛します。`case x` の `in P` 分岐も同じパターンを取ります。

| パターン | 一致するもの |
|---|---|
| 型名: `Integer`, `String`, `Tuple`, `Hash`, `Point`, `Record`, `IO`, ... | その型（型タグ）の値 |
| `nil`, `true`, `false`, `1`, `"s"`, `:ok` | 同じ型の等しい値 |
| `P \| Q` | どちらか |
| `{x:, y: name}` | そのフィールドを持つ Record。ローカル `x` と `name` を束縛 |
| `[P, Q]` | その長さの Tuple で、各位置が `P`、`Q` に一致するもの（入れ子可） |
| `x`（`[...]` の中、または単独の裸の名前） | 何でも。ローカル `x` を束縛 |

この表に無いパターン（`*rest`、find パターン、ピン `^x`、ガード、`Integer => n` の形）は未対応で、静的エラーです（[Ruby との違い](a1-ruby.md)）。

### ディスパッチではない

一致は型タグと値の比較です。`===` は無く、`case`/`when` は使えません。型名のパターンは値の型タグを見るだけで、`class B < A` の B が `A` に一致することもありません（[クラス](07-classes.md)）。

### 束縛

Record パターンと Tuple パターンは、要素をローカル変数に取り出します。`{x:}` はフィールド `x` を同名のローカルに、`{y: name}` はフィールド `y` をローカル `name` に束縛します。`P => name` は、パターン `P` が一致したものを、`P` の型に絞って束縛します: `in [Integer => code, String => body]`。

```ruby
pt = {x: 3, y: 4}
pt => {x:, y: why}
p(x)                                 # => 3
p(why)                               # => 4
pair = [1, "one"]
case pair
in [n, s] then p([s, n])             # => ["one", 1]
end
p((pair in [Integer, String]))       # => true
p((pair in [String, Integer]))       # => false
case pair
in [Integer => n, String => s] then p(String.upcase(s) * n)   # => "ONE"
end
```

### 絞り込み

`if x in Integer` の中と、`case x` の各 `in` 分岐で、ローカル `x` は一致する型に絞られます。`else` と後続の分岐は残りの型を見ます。`Integer | String` のような和を `type` の報告なしに使うのはこの方法です（前の節の「型で絞る」）。

```ruby
def pick(flag) = flag ? 1 : "one"
def f(x)
  case x
  in Integer then x + 1
  else String.size(x)
  end
end
p(f(pick(true)))                     # => 2
p(f(pick(false)))                    # => 3
```

### 網羅性

`else` の無い `case` が、来うる**型**を取り残すときは `type` として報告されます。型の集合は閉じているので、検査器はこれを検査できます。

```ruby error
def show(x)
  case x                             # !> case/in: no `in` branch matches String [type]
  in Integer then "int"
  end
end
p(show(41))
p(show("abc"))
```

Symbol リテラルは値として追跡されます。`op` がそのリテラルしか持たないなら、`case op in :add ... in :sub` は完全です。

```ruby
def name(op)
  case op
  in :add then "plus"
  in :sub then "minus"
  end
end
p(name(:add))                        # => "plus"
p(name(:sub))                        # => "minus"
```

リテラルの分岐が開いた型（ある String、Integer、実行時に作った Symbol）の**値**を取り残しうるときは、`exhaustive` 項目（レベル 3）です。プログラムは正しいかもしれず、そうでなければ `NoMatchingPatternError` が止めます。次の例はレベル 2 では走り、`--strict=3` で報告されます。

```ruby error
def name(op)
  case op                            # !> case/in: no `in` branch matches some values of String [exhaustive]
  in "add" then "plus"
  in "sub" then "minus"
  end
end
p(name("add"))
p(name(String.downcase("SUB")))
```

### 主張: x => P

`x => P` の後、ローカル `x` は `in` 分岐と同じく一致する型に絞られます。`initialize` の中では、新しいインスタンスのフィールド `@x` も同じです。「port は Integer だ」のような事実を、値を格納する場所に書く方法です: `p => Integer` の後 `@port = p`。

- 確実に一致しない値は `type`（レベル 1）として報告されます。
- 一致しないかもしれない値（別の型も来うる）は実行時に検査され、`exhaustive`（レベル 3）としてだけ報告されます。失敗は `NoMatchingPatternError` で、Ruby と同じく rescue できます。
- `x => P` は nil の検査でもあるので、nil かもしれない値は報告されません。`Array.fetch` が添字の外れを検査するのと同じ扱いです。

```ruby error
x = "abc"
x => Integer                         # !> `=> Integer`: the value is String, which does not match [type]
```

```ruby
def pick(flag) = flag ? 1 : nil
x = pick(true)
x => Integer
p(x + 1)                             # => 2
```

### 括弧

Ruby と同じく、引数の位置の `x in P` は括弧で囲みます: `p((x in Integer))`。`x in T ? a : b` や `cond && x in T` も意図と違う解析になるので、`(x in T)` と括ります。

```ruby
x = 1
p((x in Integer))                    # => true
r = (x in Integer) ? "int" : "other"
p(r)                                 # => "int"
p(x > 0 && (x in Integer))           # => true
```

```ruby error
x = 1
p(x in Integer)                      # !> syntax error: unexpected 'in'; expected a `)` to close the arguments
```

# クラス

プログラムが定義する型はクラスです。`class` に `attr_*` の行で宣言しても `Struct.new(:x, :y)` で作っても同じもので、値はフィールドを持ち（Ruby の Struct の値として `#<struct Point x=3, y=4>` と表示されます）、操作は `Point.norm2(pt)` と型を付けて呼びます。クラスは継承せず、値へのメソッド呼び出しも無いので、Ruby の class と重なるのは「型を宣言し、その操作をまとめる」ところです。

この章の例の `# => 値` は `bin/sake --strict=2` の実際の出力です。

## 型の宣言: class と attr_*

`class C ... end` は型 `C` を宣言します。本体の `attr_*` の行がフィールドを、`def` が操作を定めます。`C.new` が値を作り、フィールドはリーダ `C.x(c)` とライタ `C.set_x(c, v)` で読み書きします。

```ruby
class Account
  attr_reader owner
  attr_accessor balance
  def initialize(a)
    @balance = 0 if @balance == nil
  end
end
acct = Account.new("ko1")
p(acct)                              # => #<struct Account owner="ko1", balance=0>
p(Account.owner(acct))               # => "ko1"
Account.set_balance(acct, 100)
p(Account.balance(acct))             # => 100
rich = Account.new("you", 500)
p(Account.balance(rich))             # => 500
```

すべての `class` は型です。フィールドは最初の `class` の本体で宣言します。後の `class Account` は関数を足すだけです。フィールド名は裸で書きます。

| 行 | 意味 |
|---|---|
| `attr_accessor x, ...` | リーダ `C.x(c)` とライタ `C.set_x(c, v)` を持つフィールド |
| `attr_reader x, ...` | リーダだけ。型の関数の中では `@x = v` で書ける |
| `attr_writer x, ...` | ライタだけ。型の関数の中では `@x` で読める |
| `private attr_... x` | リーダとライタはそのクラス自身の関数専用。`new` は受け取る |

`private` のフィールドは、そのクラスの関数からならどの値のものでも読み書きできます（`@x`、または `T.x(other)`）。外からの `T.x(c)` は静的エラーです。

```ruby
class Counter
  attr_reader label
  private attr_accessor n
  def bump(c) = @n += 1
  def same?(c, other) = n(c) == n(other)
end
c = Counter.new("hits", 0)
Counter.bump(c)
p(Counter.bump(c))                   # => 2
p(Counter.same?(c, Counter.new("x", 2)))   # => true
```

```ruby error
class Counter
  attr_reader label
  private attr_accessor n
end
c = Counter.new("hits", 0)
p(Counter.n(c))                      # !> field `n` of Counter is private (private attr_*)
```

### フィールドの順序と new

フィールドは書いた順に並び、行をまたいでも同じです。これが `C.new` の引数の順です。`C.new` はアクセスの種類に関わらずフィールドを位置で取り、名前でも取れます。`Logger.new("app", level: :warn)` は最初のフィールドを位置で、`level` をキーワードで与えます。

- フィールドが複数ある型では名前を勧めます。位置の `new` はフィールド順と照合されません。
- 未知の名前と、1 つのフィールドの二重指定は静的エラーです。
- `initialize` が無ければ、全フィールドを与えます。
- `initialize` があれば、後ろのフィールドを省略できます。後のキーワードのために飛ばすこともできます。省略したフィールドは initialize が始まるとき nil で、initialize が設定します。

```ruby
class Logger
  attr_reader name, level
  def initialize(l)
    @level = :info if @level == nil
  end
end
a = Logger.new("app")
p(Logger.level(a))                   # => :info
b = Logger.new("app", level: :warn)
p(Logger.level(b))                   # => :warn
c = Logger.new(level: :debug, name: "db")
p(c)                                 # => #<struct Logger name="db", level=:debug>
```

```ruby error
class Logger
  attr_reader name, level
  def initialize(l)
    @level = :info if @level == nil
  end
end
Logger.new("app", lvl: :warn)        # !> Logger has no field `lvl`
```

### initialize

class の `def initialize(c)` は、`C.new` がフィールドを格納した**後**に、新しいインスタンスを受けて走ります。Ruby と同じく、最初の値（`@items = Any[]`）、検査（`@port => Integer`）、変換（`@celsius = Float(@celsius)`）を書く場所です。`@level = :info if @level == nil` は `new` が与えた値を保ちます。

- 引数はその 1 つ（新しいインスタンス）だけです。2 つ以上は静的エラーです。
- `C.initialize` を直接呼ぶのは静的エラーです。`C.new` が呼びます。
- 検査器は initialize を `C.new` の呼び出しごとに解析します。そこで `@x` はその呼び出しが与えた値を読むので、誤った引数はその呼び出しについて報告されます。フィールドは initialize が残したものを持ちます。

```ruby
class Temp
  attr_reader celsius, label
  def initialize(t)
    @celsius = Float(@celsius)
    @label = "C" if @label == nil
  end
end
t = Temp.new(21)
p(Temp.celsius(t))                   # => 21.0
p(Temp.label(t))                     # => "C"
p(Temp.new(1, "K"))                  # => #<struct Temp celsius=1.0, label="K">
```

```ruby error
class Box
  attr_reader value
  def initialize(b)
    @value => Integer                # !> `=> Integer`: the value is String, which does not match [type]
  end
end
p(Box.new(1))
p(Box.new("s"))
```

> [!WARNING]
> Ruby の `def initialize(x) = @x = x` は Sake では静的エラーです。`x` は新しいインスタンスであって値ではなく、自分を自分のフィールドに入れることになります。`C.new(...)` が既にフィールドを格納しているので、initialize は検査と変換だけを書きます。

```ruby error
class Box
  attr_reader value
  def initialize(x) = @value = x     # !> `@value = x` stores the new Box in its own field: `x` is the instance, not a value
end
```

### 既定値は無い

`attr_reader items = Any[]` は静的エラーです。フィールドの最初の値は `initialize` で設定します。新しいインスタンスごとに走る唯一の場所がそこで、他のフィールドも読めます（`@len = String.bytesize(@src)`）。検査器は initialize を通してフィールドを追うので、initialize が常に設定するフィールドはその後 nil ではありません。

```ruby error
class Bag
  attr_reader items = Any[]        # !> a field has no default value; set it in initialize, which runs after Bag.new
end
```

```ruby
class Bag
  attr_reader items
  def initialize(b)
    @items = Any[] if @items == nil
  end
  def add(b, x) = Array.push(@items, x)
end
b = Bag.new
Bag.add(b, 1)
p(Bag.items(b))                      # => [1]
```

### 予約語と同じ名前のフィールド

予約語と同じ名前のフィールドは Symbol で宣言します: `attr_accessor :next`。裸では解析できません。リーダは `Node.next(n)`、関数の中の `@next` はいつもどおりです。

```ruby
class Node
  attr_accessor value, :next
  def last_value(n)
    nx = @next
    nx ? last_value(nx) : @value
  end
end
list = Node.new(1, Node.new(2, nil))
p(Node.next(Node.next(list)))        # => nil
p(Node.last_value(list))             # => 2
```

### 構築ごとに 1 つの型

検査器にとって、各 `C.new` はそれ自身の型です。別の場所で作ったインスタンスはそれぞれのフィールド型を保つので、Integer の `Heap` と String の `Heap` は混ざりません。1 つの `C.new` が別の引数型で呼ばれた関数の中にあるとき（`expect(42)` と `expect("x")`）も、呼び出しごとに型が分かれます。汎用の包み（`Result.map` の `Ok.new(yield(@value))`）は呼び出し元ごとに 1 つの型です。

- メッセージは、型に複数の場所があるときだけ場所付きで名乗ります（`Heap@L7`）。
- 値から値を作る関数（Value を取る関数の中の `Value.new(a + b)`）は、場所ごとに 1 つの型にとどまります。

```ruby
class Heap
  attr_reader items
  def push(h, x) = Array.push(@items, x)
  def top(h) = Array.first(@items)
end
ints = Heap.new(Any[])
Heap.push(ints, 3)
words = Heap.new(Any[])
Heap.push(words, "job")
p(Heap.top(ints) + 1)                # => 4
p(String.upcase(Heap.top(words)))    # => "JOB"
```

### class B < A

`class B < A` は A の定義を B に書き写す略記で、継承ではありません。

- A のフィールドが先、次に B のフィールドが並びます。
- A の関数は B の関数でもあります。その中の型無しの名前と `@x` は B のものです。
- A の `include` は B のものです。
- B 自身の定義が A のものに勝ちます。
- その後 A と B は無関係です。B は A ではなく、`A.f(b)` は型エラーで、`b in A` は偽です。
- `<` はプログラムのどの class でも取り、その場に書いた `Struct.new(...)` も取ります（`class P < Struct.new(:x)`）。module は `include` します。

```ruby
class Shape
  attr_reader name
  def describe(s) = "a shape called " + @name
end
class Circle < Shape
  attr_reader r
  def area(c) = 3.0 * @r * @r
end
class Square < Shape
  attr_reader side
  def describe(s) = "a square called " + @name
end
c = Circle.new("c1", 2.0)
p(c)                                 # => #<struct Circle name="c1", r=2.0>
p(Circle.describe(c))                # => "a shape called c1"
p(Circle.area(c))                    # => 12.0
p(Square.describe(Square.new("s1", 3.0)))   # => "a square called s1"
```

```ruby error
class Shape
  attr_reader name
  def describe(s) = @name            # !> Shape.name: argument 1 must be Shape, but is Circle [type]
end
class Circle < Shape
  attr_reader r
end
p(Shape.describe(Circle.new("c", 2.0)))
```

### 例外型

`class E < Exception`（または `< StandardError`）は例外型を宣言します。`message` が最初のフィールドで、その後に `attr_*` の行のフィールドが続きます。`message` より後のフィールドは常に省略でき、`E.new("msg")` はメッセージだけ与えます。`raise E, "msg"` の形は、`message` 以外のフィールドを持たない例外型に限ります（[例外とエラー](08-exceptions.md)）。

```ruby
class ParseError < StandardError
  attr_reader line
end
begin
  raise ParseError.new("bad token", 7)
rescue ParseError => e
  p(ParseError.message(e))           # => "bad token"
  p(ParseError.line(e))              # => 7
end
begin
  raise ParseError.new("no line")
rescue ParseError => e
  p(ParseError.line(e))              # => nil
end
```

### 略記: Struct.new と Exception.new

`Struct.new(:x, :y)` は `attr_accessor x, y` を持つ `class C` の略記です。Ruby の形 `class C < Struct.new(:x, :y)` も書け、そのフィールドが先、本体の `attr_*` 行と関数が後に来ます。`Exception.new(:line)` は `attr_accessor line` を持つ `class C < Exception` の略記です。

```ruby
class Point < Struct.new(:x, :y)
  attr_reader label
  def to_s(pt) = @label + "(" + Integer.to_s(@x) + ", " + Integer.to_s(@y) + ")"
end
p(Point.to_s(Point.new(1, 2, "P")))  # => "P(1, 2)"
Oops = Exception.new(:line)
begin
  raise Oops.new("oops", 3)
rescue Oops => e
  p(Oops.line(e))                    # => 3
end
```

### 宣言の静的エラー

次はどれも静的エラーで、検査器が hint で直し方を示します。

- `attr_reader :x`: 予約語でないフィールドを Symbol で書いた（裸で書く）。
- 最初の `class C` より後の `class C` でフィールドを宣言した。
- 既定値 `attr_reader x = v`。
- 読み出し専用（`attr_reader`）のフィールドへの、クラスの外からの書き込み。
- 古い形 `class C < {reader: [...]}`。hint が `attr_*` の行を示します。

## Struct.new の操作

```ruby
Point = Struct.new(:x, :y)
```

名前空間 `Point` に次の操作が定義されます。

| 操作 | 意味 |
|---|---|
| `Point.new(x, y)` | 作成。位置引数、フィールドごとに 1 つ |
| `Point.x(p)`, `p.Point.x` | フィールド `x` を読む（リーダはフィールドの名前） |
| `Point.set_x(p, v)`, `p.Point.x = v` | フィールド `x` をその場で書く。`v` を返す |
| `p.Point.x += v`, `\|\|=`, `&&=` | `p.Point.x = p.Point.x + v`。`p` は 1 度だけ評価 |
| `Point[p1, ...]` | Point の Array |
| `p == nil`, `p != nil` | nil との比較 |

```ruby
Point = Struct.new(:x, :y)
pt = Point.new(3, 4)
p(pt)                                # => #<struct Point x=3, y=4>
p(Point.x(pt))                       # => 3
p(Point.set_x(pt, 10))               # => 10
pt.Point.y += 1
p(pt)                                # => #<struct Point x=10, y=5>
pts = Point[Point.new(1, 2), Point.new(3, 4)]
p(pts)                               # => [#<struct Point x=1, y=2>, #<struct Point x=3, y=4>]
p(pt == nil)                         # => false
```

### 可変性

値は可変で、参照で共有されます。ある変数を通した変更は、同じ値を持つ他のすべての変数から見えます。

```ruby
Point = Struct.new(:x, :y)
pt = Point.new(3, 4)
q = pt
Point.set_y(q, 0)
p(pt)                                # => #<struct Point x=3, y=0>
```

### 操作を足す

`class Point ... end` か `def Point.f` で自分の操作を足します。その中ではリーダとライタを型無しで呼べます（`x(p)`、`set_x(p, v)`）。フィールドと同名の関数（`def x(p) = ...`）は、Ruby で attr_accessor の後にメソッドを定義したのと同じくリーダを置き換え、ライタと同名の関数（`def set_x(p, v)`）はライタを置き換えます（`p.Point.x = v` と `+=` もそれを呼びます）。`@x` は常にフィールドを読み書きします。

```ruby
Point = Struct.new(:x, :y)
def Point.shift(pt, dx)
  @x += dx
  pt
end
class Point
  def norm2(pt) = @x * @x + @y * @y
  def x(pt) = 100
end
pt = Point.new(3, 4)
p(Point.shift(pt, 1))                # => #<struct Point x=4, y=4>
p(Point.norm2(pt))                   # => 32
p(Point.x(pt))                       # => 100
```

### 名前でフィールドを扱う

`Point.field_names` はフィールドの名前を Symbol で並べた Array です（Ruby の `Struct.members`）。`Point.read_field(p, name)` と `Point.write_field(p, name, v)` は、Symbol が名指すフィールドを `@x` と同じく読み書きします（Struct での Ruby の `p[name]` と `p[name] = v`）。Hash への変換や表の行からの読み込みのように、全フィールドをたどるコードを 1 度だけ書けます。

```ruby
Point = Struct.new(:x, :y)
pt = Point.new(3, 4)
p(Point.field_names)                 # => [:x, :y]
p(Array.map(Point.field_names) { |f| Point.read_field(pt, f) })   # => [3, 4]
Point.write_field(pt, :y, 10)
p(Point.read_field(pt, :y) + 1)      # => 11
```

- リテラルの名前はそのフィールドです。`Point.read_field(pt, :y)` は `y` の型を持ち、`:z` は静的なエラーです（「Point has no field :z」）。リテラルに絞られた Symbol（`case name in :x | :y`）はそのフィールドだけに届きます。
- それ以外の Symbol は、全フィールドの型の和を読み、検査器から見ると値を全フィールドに書きます。フィールドごとの型を保つには、名前の `case` の中で書きます: `in :id then Post.write_field(post, name, Integer(v))`。
- どのフィールドも名指さない Symbol は `KeyError` です。
- クラスの関数の外では、名前が届きうるフィールドに公開のリーダ（`read_field`）かライタ（`write_field`）が要ります。中では private も含めた全フィールドです。基底クラスの関数（`class B < A`）は、A に `id` が無くても `read_field(b, :id)` で B のフィールドを読めます。

### フィールドの略記 @x

クラスの関数（`class Point` の中、または `def Point.f`）の中で、`@x` は関数の**第 1 引数**のフィールド `x` です。第 1 引数は慣習として主語です。

| 書いたもの | 意味 |
|---|---|
| `@x` | `Point.x(p)` |
| `@x = v` | `Point.set_x(p, v)` |
| `@x OP= v` | `Point.set_x(p, Point.x(p) OP v)` |
| `@x \|\|= v` | `Point.x(p) \|\| Point.set_x(p, v)` |

- `p` は第 1 引数の今の値で、同名の引数を持つブロックの中でも変わりません。
- 通常の実行時検査がかかります。第 1 引数は Point でなければなりません。
- `@x` は次の場合に静的エラーです: クラスの関数の外、引数の無い関数、フィールドが存在しないとき。

```ruby error
Point = Struct.new(:x, :y)
def far(pt) = @x > 100               # !> `@x` means a field of the first argument, so it is only available in a function of a class
```

### 印字

`p` は クラスのインスタンスを `#<struct Point x=1, y=2>` と印字します。`puts` も同じです。

### Struct.new の制限

`Struct.new` は定数に代入しなければなりません。定数はトップレベルか、class / module の本体の直下に置きます（`module Geo` の中の `Point = Struct.new(:x, :y)` は `Geo::Point`）。Symbol だけを取り、ブロックは取りません。関数は `class Point` の中で定義します。

`Data.define` は無く、`Struct.new` を使う hint 付きで拒否されます。Ruby の `Data` は不変ですが、Sake の名前付き型は可変で、それは Ruby の `Struct` が提供するものです。

```ruby error
Point = Data.define(:x, :y)          # !> Sake's named types are mutable, so they are made with Struct.new, not Data.define
```

### 複製: Kernel.dup

`Kernel.dup(x)` は浅い複製です。新しい容器と クラスのインスタンスを作り、要素は同じものを共有します。型が `dup` を定義していればそれが呼ばれます。

```ruby
Point = Struct.new(:x, :y)
a = Point.new(1, Any[2])
b = Kernel.dup(a)
Point.set_x(b, 9)
Array.push(Point.y(b), 3)
p(a)                                 # => #<struct Point x=1, y=[2, 3]>
p(b)                                 # => #<struct Point x=9, y=[2, 3]>
```

# 例外とエラー

Sake の例外は Ruby と同じ字面で書きます: `raise` で投げ、`begin`/`rescue`/`else`/`ensure` で受け、`retry` でやり直します。違いは 2 つです。例外型は普通のクラスで、型をまとめるのは継承ではなくモジュールであること。そして検査器が、各関数からどの例外が漏れうるかを実行前に追うことです。この章の前半が例外の書き方、後半が静的エラーと実行時エラーの種類の一覧です。エラーの表示形式は[概要と実行](01-overview.md)にあります。

## 例外

```ruby
ParseError = Exception.new(:line)        # フィールド: message, line

def parse(s)
  raise ParseError.new("empty", 1) if s == ""
  Integer(s)
end

begin
  parse("")
rescue ParseError => e
  p(ParseError.line(e))                  # => 1
rescue KeyError, IndexError => e
  p(Exception.message(e))
rescue => e                              # rescue できるすべての例外
  raise                                  # 再送出
else
  p(:ok)                                 # 何も投げられなかったとき
ensure
  p(:ensure)                             # => :ensure
end
```

形は Ruby のままです。以下の節で、例外型の宣言、`raise` と `rescue` の各形、検査器が見るもの、捕まえられなかったときの振る舞いを順に述べます。

### 例外型の宣言

例外型はクラスです（[クラス](07-classes.md)）。最初のフィールドが `message` で、その後に自分で宣言したフィールドが続きます。他のクラスと同じく `Name.new("msg", ...)`、`Name.message(e)`、`Name.field(e)`、関数の中の `@field` が使えます。

```ruby
class ParseError < Exception
  attr_reader line
end

e = ParseError.new("empty", 1)
p(ParseError.message(e))                 # => "empty"
p(ParseError.line(e))                    # => 1
p(e)                                     # => #<ParseError: empty line=1>
```

- **2 つの書き方。** `class Name < Exception` に `attr_reader field` の行を書く形と、その略記 `Name = Exception.new(:field, ...)` は同じものです。
- **まとめるのはモジュール。** `class B < A` は書き写しで、`rescue A` は B を捕まえません。例外型をまとめるには、モジュールを include させて `rescue M` と書きます（[下](#モジュールでまとめる)）。組み込みの型は Ruby の親子関係のとおりで、`rescue IndexError` は `KeyError` を、`rescue IOError` は `EOFError` を、`rescue RangeError` は `FloatDomainError` を、`rescue ArgumentError` は `Math::DomainError` も捕まえます。`class ConvError < RangeError` のように組み込みの例外を親に書いたクラスも、`rescue RangeError` で捕まります。
- **組み込みの例外型。** 組み込みの操作が投げる型で、フィールドは `message` だけです: `RuntimeError`、`ArgumentError`、`TypeError`、`KeyError`、`IndexError`、`ZeroDivisionError`、`RangeError`、`IOError`、`EOFError`、`RegexpError`、`FloatDomainError`、`EncodingError`、`ThreadError`、`NoMatchingPatternError`、`Math::DomainError`。それぞれの詳細は[組み込みリファレンスの Exceptions](ref/Exceptions.md)にあります。

### raise の形

`raise` は構文で、操作ではありません。4 つの形があります。

| 書いたもの | 投げるもの |
|---|---|
| `raise "msg"` | `RuntimeError` |
| `raise T, "msg"` | `T.new("msg")`。T のフィールドは `message` だけ |
| `raise value` | その例外値 |
| `raise`（rescue 節の中で） | 今受けている例外の再送出 |

```ruby
begin
  raise "boom"
rescue => e
  p(e)                                   # => #<RuntimeError: boom>
end
begin
  raise KeyError, "no such key"
rescue KeyError => e
  p(e)                                   # => #<KeyError: no such key>
end
begin
  raise IndexError.new("out")
rescue IndexError => e
  p(Exception.message(e))                # => "out"
end
```

`message` 以外のフィールドを持つ型は `raise T, "msg"` では投げられません。値を作って `raise T.new(...)` と書きます。

```ruby error
E = Exception.new(:code)
raise E, "msg"                           # !> E has fields besides message; raise it with `raise E.new(...)`
```

### rescue

`rescue A, B => e` は列挙した型を捕まえます。書いた名前がモジュールなら、それを include した例外型を、組み込みの親（`IndexError` など）なら Ruby の子も捕まえます。

すべてを捕まえるには `rescue => e` と書きます。`rescue StandardError => e` と `rescue Exception => e` も同じ意味です。このとき `e` の型は和なので、型ごとに処理を分けるには `case e in A ...` で絞ります（[制御構造とパターン](06-control.md)）。

```ruby
def check(x)
  raise ArgumentError, "negative" if x < 0
  x
end
begin
  check(-1)
rescue ArgumentError, ZeroDivisionError => e
  v = case e
      in ArgumentError then "argument"
      in ZeroDivisionError then "zero"
      end
  p(v)                                   # => "argument"
end
```


### モジュールでまとめる

Ruby のライブラリは、例外を `class Error < StandardError` の子にして `rescue MyLib::Error` でまとめて受けます。Sake では親をモジュールにして、各例外型に include させます。`rescue M => e` は M を include したすべての例外型（M を include したモジュールを include する型も）を捕まえ、`e` の型はそれらの和です。モジュールの関数 `M.f(e)` は、型ごとの定義に振り分けられます。

```ruby
module ParseFailure
  def describe(e) = "parse: " + Exception.message(e)
end
class BadToken < StandardError
  include ParseFailure
end
class Unclosed < StandardError
  include ParseFailure
  attr_reader line
end
def parse(s)
  raise BadToken, "bad token" if s == "?"
  raise Unclosed.new("unclosed", 3) if s == "("
  s
end
begin
  parse("(")
rescue ParseFailure => e
  p(ParseFailure.describe(e))            # => "parse: unclosed"
  case e
  in Unclosed then p(Unclosed.line(e))   # => 3
  in BadToken then p("token")
  end
end
```

モジュールは投げられません（`raise ParseFailure, "x"` は静的エラー）。Ruby で親クラス自身も投げているなら、具体的な型を 1 つ足して include させます。レベル 1 は、前の `rescue M` がもう受けている型の `rescue A` で止めます。begin の本体がモジュールのどの型も投げない `rescue M` は `unused-rescue` の警告です。

```ruby error
module ParseFailure
end
class BadToken < StandardError
  include ParseFailure
end
def parse(s)
  raise BadToken, "bad token" if s == "?"
  s
end
begin
  parse("?")
rescue ParseFailure => e
  p(1)
rescue BadToken => e                     # !> rescue BadToken: an earlier rescue (ParseFailure) already catches it [rescue]
  p(2)
end
```

### メッセージを読む

`Exception.message(e)` は、どの型の例外値からもメッセージを読みます。`e` の型が和のときに使います。型が決まっているなら `ParseError.message(e)` でも同じです。

組み込みの操作が投げた例外のメッセージは Ruby の文です。rescue されずにプログラムを終えたときの報告には、操作名も付きます（`ZeroDivisionError: Arithmetic./: divided by 0`）。

```ruby
begin
  p(1 / 0)
rescue ZeroDivisionError => e
  p(Exception.message(e))                # => "divided by 0"
end
```

### バックトレースと原因

`Exception.backtrace(e)` は、例外が投げられたときの呼び出しの列を、Ruby と同じ `"FILE:LINE:in 'FUNCTION'"` の String の Array で返します。内側が先です。まだ投げていない例外値（`E.new` で作っただけのもの）では nil です。`raise e` や引数のない `raise` で投げ直しても、最初に投げたときの列のままです。

`Exception.cause(e)` は、`e` が投げられたときに rescue 節で扱っていた例外を返します。無ければ nil です。どちらも nil になりうるので、`--strict` では使う前に確かめます。

Ruby と違い、組み込みの操作の中の行（Ruby の `'Integer#/'` など）は列に入りません。

```ruby
def parse(s)
  Integer(s)
rescue ArgumentError
  raise "not a number: #{s}"
end

begin
  parse("x")
rescue => e
  bt = Exception.backtrace(e)
  p(Array.map(bt) { |l| String.sub(l, /\A.*?:/, "") }) if bt   # => ["4:in 'parse'", "8:in '<main>'"]
  c = Exception.cause(e)
  p(c) if c                                # => #<ArgumentError: invalid value for Integer(): "x">
end
p(Exception.backtrace(RuntimeError.new("not raised")))   # => nil
```

### プログラムの誤り

`SystemStackError`、`LocalJumpError`、`NotImplementedError` はプログラムの誤りで、rescue できません。`rescue` に書くのは静的エラーです。

```ruby error
begin
  p(1)
rescue SystemStackError => e             # !> SystemStackError cannot be rescued: it is a program error, which the checks before running report
  p(e)
end
```

`TypeError`（誤った型の値を受けた操作）と `NoMatchingPatternError` は Ruby と同じく rescue できます。ただし、それらが報告する型の誤りの多くは、実行前の検査が止めます（[概要と実行](01-overview.md)）。次の例は既定のレベルでは `type` の問題として実行前に止まります。`--strict=0` で走らせると `len(1)` は `TypeError` を投げ、他の例外と同じく rescue できて、メッセージは `"argument 1 must be String, got Integer"` です。

```ruby error
def len(x)
  String.length(x)                       # !> String.length: argument 1 must be String, but is Integer [type]
end
begin
  len(1)
rescue TypeError => e
  p(Exception.message(e))
end
```

### 他の形

`def f ... rescue ... end`、修飾子の `expr rescue fallback`、`retry` は Ruby と同じです。`ensure` は begin ブロックを離れるときに 1 度走ります。`return` や `exit` で離れるときも走ります。

```ruby
def safe_div(a, b)
  a / b
rescue ZeroDivisionError
  0
end
p(safe_div(6, 0))                        # => 0

n = Integer("x") rescue -1
p(n)                                     # => -1

tries = 0
begin
  tries += 1
  raise "again" if tries < 3
rescue RuntimeError
  retry
end
p(tries)                                 # => 3
```

### 例外の流れの検査

検査器は、明示的に `raise` した型のうちどれが各関数から出うるかを追います。2 つの項目がこれを使います（レベルは[概要と実行](01-overview.md)）。

- **`unused-rescue`（レベル 1〜4 で警告。レベル 0 は型推論を走らせない）。** begin 本体が決して投げない型の rescue 節を報告します。`ZeroDivisionError` のような組み込みの種類は普通の操作から来うるので、常にありうるとみなし、報告しません。プログラムは走ります。防御的な `rescue` は普通に書くもので、投げるものがあるかはプログラム全体で決まるからです（一部のアプリしか投げない例外を受けるライブラリの `rescue`）。`--strict=2,unused-rescue` でエラーになります。関連する `rescue` 項目（レベル 1）は、前の節が既に捕まえる節で止めます。
- **`unrescued`（レベル 4）。** rescue されずにトップレベルまで届きうる `raise` を報告します。`raise: RuntimeError may reach the top level without being rescued [unrescued]` のような報告です。

```ruby
ParseError = Exception.new(:line)
begin
  p(Integer("1"))                        # => 1
rescue ParseError => e                   # warning: the begin body never raises ParseError [unused-rescue]
  p(e)
end
```

### 捕まえられなかった例外

rescue されなかった例外は、実行時エラーと同じ形でプログラムを終えます: `FILE:LINE: in FUNCTION: ParseError: message`。終了コードは 1 です。

```ruby error
def check(x)
  raise ArgumentError, "x must be positive" if x <= 0   # !> ArgumentError: x must be positive
  x
end
check(0)
```

### デッドロック

すべてのスレッドが待ちになると、プログラムは Sake の `ThreadError` で終わります。何も push されない `Queue.pop`、自分の中で再び取る `Mutex.synchronize`、互いを待つ `Thread.join` がその例です（[組み込み操作](09-builtins.md)）。

```ruby error
q = Queue.new
Queue.pop(q)                             # !> ThreadError: deadlock: every thread is waiting
```

## 静的エラーの種類

静的エラーは位置順にまとめて報告され、何も実行されません。終了コードは 2 です。形式は[概要と実行](01-overview.md)にあります。

| 種類 | 例 |
|---|---|
| 構文エラー | Prism が解析できないもの |
| 未定義の型、操作、関数 | `String.upcse(s)` |
| 引数の数の誤り | |
| ブロックの過不足 | 取らないところへのブロック、必要なところでの欠落 |
| 値へのメソッド呼び出し | `name.upcase` |
| 禁止構文 | 下記 |
| 未対応の構文 | 付録 [Ruby との違いと未対応のもの](a1-ruby.md) |
| 二重定義 | |
| `T[...]` のリテラルの型の不一致 | `Integer["a"]` |
| `--strict` で選んだ項目 | 既定では、型が合わない値 |

禁止構文は、`send`、`public_send`、`__send__`、`method_missing`、`define_method`、`eval` の仲間、`instance_variable_get`/`set`、`const_get`/`set`、`binding`、`self`、そしてクラスの関数の外の `@x` です。どれも呼び出し先を実行時まで決められなくするか、Sake に無い概念（インスタンスの状態）を指すものです。

## 実行時エラーの種類

実行時エラーは、その操作の行でプログラムを止めます。終了コードは 1 です。どれも例外なので `rescue` できます。例外は `SystemStackError` と、すべてのスレッドが待ちになって検出されるデッドロックです（`Mutex.synchronize` の再入の `ThreadError` は rescue できます）。

| 種類 | 投げるもの |
|---|---|
| `TypeError` | 誤った型の値を受けた操作（下記） |
| `IndexError` | 範囲の外の添字（下記） |
| `ArgumentError` | ブロックの引数の数。負のサイズ。`Integer ** 負`。`sort` で比べられない値 |
| `ZeroDivisionError` | Integer の `/` か `%` のゼロ除算 |
| `KeyError` | 無いキーの `Hash.fetch`。無いフィールドを名乗る Record パターン |
| `RangeError` | 有限の Range が要る操作に終端の無い Range |
| `RegexpError` | 不正なパターンの `Regexp.new` |
| `IOError` | ファイル・ディレクトリ・ソケットの失敗（下記） |
| `EOFError` | 組み込みは投げません（下記） |
| `EncodingError` | エンコーディングの合わない String の操作 |
| `FloatDomainError` | NaN や Infinity の Integer への変換 |
| `Math::DomainError` | `Math.sqrt(-1)` など |
| `SystemStackError` | 10,000 より深い再帰 |
| `ThreadError` | デッドロック |

- **`TypeError`。** 誤った型の値を受けた操作。左のオペランドの型が支えない演算子。型付き Array への別の型の書き込み。Tuple でも Array でもない値からの多重代入。
- **`IndexError`。** Tuple の外の添字。Array の外の `Array.fetch`。T の Array の末尾の先への書き込み（`xs[5] = 3`。隙間が nil になるため）。
- **`IOError`。** `File.read`、`Dir.mkdir` などの失敗。Ruby では `Errno::ENOENT` などで、メッセージは Ruby のものです。ソケットのエラー（拒否、リセット、未知のホスト）も `IOError` です。
- **`EOFError`。** 組み込みの操作は投げません。終端の読み出しは nil や `""` を返し、Ruby の EOFError は `IOError` に畳みます。型としては存在するので `rescue` に書けます。

```ruby error
h = Hash.of("a" => 1)
p(Hash.fetch(h, "b"))                    # !> KeyError: Hash.fetch: key not found: "b"
```

# 組み込み操作

組み込みの操作は約 550 あり、名前は Ruby のコアライブラリと同じです。この章は名前空間ごとの案内です: その型が何のためにあるか、最初に手が伸びる 2〜3 の操作、短い例、そして詳細のある章へのリンクを置きます。**各操作の正確な署名、引数、nil になる場合、投げる例外、例は、第 2 部「組み込みリファレンス」に型ごとに 1 章ずつあります**（[Array](ref/Array.md)、[String](ref/String.md)、[Hash](ref/Hash.md)、[Kernel](ref/Kernel.md)、…）。

各節の表は「何をしたいか」で操作をまとめたもので、「結果」の列は結果の型です。「ブロック」と記したものはブロックが必須です。`[x]` は省略できる引数です。演算子（`+`、`<`、`[]`）の規則は[演算子と添字](05-operators.md)に、各型の値の性質は[値と型](03-values.md)にあります。

## Kernel

Kernel は、プログラムのどこからでも名前だけで呼べる操作の集まりです。`puts(x)`、`Integer(s)`、`loop { }` のように書き、`Kernel.puts(x)` と書く必要はありません。最初に使うのは出力の `p` と `puts`、文字列から数への変換 `Integer(s)`、繰り返しの `loop` です。詳細は [Kernel](ref/Kernel.md)。

```ruby
puts("total:", 3)
# => total:
# => 3
p(format("%05.1f", 3.14159))     # => "003.1"
p(Integer("42") + 1)             # => 43
x = loop { break 7 }
p(x)                             # => 7
p(Math.PI > 3)                   # => true
```

| 操作 | 結果 | 備考 |
|---|---|---|
| `puts(*xs)` | nil | Ruby の `puts` と同じ。Array と Tuple は 1 要素 1 行 |
| `print(*xs)` | nil | 改行なし |
| `p(x)`, `p(x, y)`, `pp(x)` | x · `[x, y]` · x | 各引数を Ruby の `inspect` の形で 1 行ずつ。`p()` は nil |
| `format(fmt, *xs)`, `sprintf` | String | Ruby の format。引数は Integer, Float, String, Symbol, nil, true, false |
| `Integer(x)`, `Float(x)`, `Rational(a, [b])`, `Complex(re, [im])` | 数 | Ruby の厳密な変換。不正な入力は `ArgumentError` |
| `rand`, `rand(n)`, `srand(seed)` | Float、または n 未満の Integer/Float | |
| `sleep(secs)` | Integer | |
| `loop { }` | `break` の値 | `break` までブロックを繰り返す |
| `dup(x)` | x の複製 | Ruby の `obj.dup`。`dup` を定義した型はそれを使う |
| `gets` | String か nil | 標準入力の 1 行 |
| `exit(status)` | | Integer、または true で 0 / false で 1（既定 0）。`ensure` は走る。その後のコードには到達しない |
| `warn(x, ...)` | nil | エラー出力へ（`puts` と同じ形） |
| `system(cmd)` | true / false / nil | Ruby の `system` |
| `at_exit { }` | nil | プログラムの終わりに走るブロック |
| `ARGV` | Array of String | プログラムの引数。Ruby の定数のように書くが操作（`Kernel.ARGV`）。毎回同じ Array なので `Array.shift(ARGV)` が効く |
| `Kernel.PROGRAM_NAME` | String | 走っているファイルの名前。`ARGV` と違い、裸では書けない（大文字の名前は型） |
| `__FILE__`、`__LINE__`、`__dir__` | String、Integer、String | このファイル（主ファイルは与えた名前、require したファイルはフルパス）、この行、このファイルのディレクトリのフルパス。Ruby と同じ: `File.join(__dir__, "views")` |
| `equal?(a, b)` | true/false | 同一性 |
| `block_given?` | true/false | 今の関数がブロックを受けたか |

- **定数は操作。** `Math::PI`、`Math::E`、`Float::INFINITY`、`Float::NAN`、`Float::EPSILON`、`Float::MAX`、`Float::MIN` は、`ARGV` と同じく操作として読みます（`Math.PI`）。Sake に値の定数は無く、組み込みの定数もこれだけです（`A::B` のような入れ子の名前は名前空間で、値ではありません）。

## Integer / Float

Integer は上限の無い整数、Float は倍精度の浮動小数点数です。算術と比較は演算子で書き、`Integer.to_s(n, 16)` のような変換と、`Integer.times(n) { }` のような繰り返しを型を付けて呼びます。最初に使うのは `/` と `%`（Integer どうしは整数除算）、`Float.round`、`Integer.times` です。詳細は [Integer](ref/Integer.md)、[Float](ref/Float.md)、[Arithmetic](ref/Arithmetic.md)。

```ruby
p(7 / 2)                         # => 3
p(7.0 / 2)                       # => 3.5
p(Integer.divmod(7, 2))          # => [3, 1]
p(Integer.to_s(255, 16))         # => "ff"
p(Float.round(3.14159, 2))       # => 3.14
Integer.times(3) { |i| print(i) }
puts                             # => 012
```

| 操作 | 結果 |
|---|---|
| `+ - * / % **` | Integer（Float なら Float） |
| `< <= > >= == !=` | true/false |
| `Integer.to_s(n, base = 10)`, `to_f`, `abs`, `succ`, `pred` | String, Float, Integer, Integer, Integer |
| `even?`, `odd?`, `zero?` | true/false |
| `times(n) { \|i\| }` · `upto(a, b) { }` · `downto(a, b) { }` · `step` | n · a · a（ブロック） |
| `& \| ^ << >>` | Integer |
| `divmod(a, b)` | `[商, 余り]` の Tuple（Float は `[Integer, Float]`） |
| `gcd`, `lcm`, `pow(a, b, [mod])`, `bit_length`, `sqrt(n)`, `clamp(n, lo, hi)` | Integer |
| `digits` · `chr` · `between?(n, lo, hi)` | Array of Integer · String · true/false |
| `Float.to_i`, `floor`, `ceil`, `truncate` · `round(f)` / `round(f, digits)` | Integer · Integer / Float |
| `nan?` · `finite?` · `infinite?` | true/false · true/false · 1, -1, nil |
| `Float.to_r`, `rationalize` | Rational |

- **どの実数も取る丸め。** `Arithmetic.round(x)`、`floor`、`ceil`、`truncate`（省略可能な桁数付き）、`abs`、`to_f`、`to_i`、`zero?` は、Ruby の `x.round` と同じくどの実数（Integer, Float, Rational）も取り、結果の型は x に従います（桁なしの round は Integer）。`Float.round` は Float だけを名乗ります。

## String

String はエンコーディングを持つ文字の並びで、可変です。名前が `!` で終わる操作は主語をその場で変え、他は新しい String を返します。最初に使うのは `String.split`、`String.sub`/`gsub`、`String.include?` と、連結の `+` です。詳細は [String](ref/String.md)。

```ruby
s = "Hello, World"
p(String.length(s))              # => 12
p(String.upcase(s))              # => "HELLO, WORLD"
p(String.split(s, ", "))         # => ["Hello", "World"]
p(String.sub(s, "World", "Sake"))   # => "Hello, Sake"
p(String.include?(s, "World"))   # => true
p(String.index(s, "x"))          # => nil
p(s + "!")                       # => "Hello, World!"
```

| 目的 | 操作 | 結果 |
|---|---|---|
| 連結・繰り返し・書式 | `+(a, b)`, `*(s, n)`, `%` | String |
| 比較 | `== != < <= > >=` | true/false |
| 長さと数 | `length`, `size`, `count(s, chars)`, `to_i(s, base = 10)` · `to_f` | Integer · Float |
| 変形 | `upcase`, `downcase`, `capitalize`, `swapcase`, `reverse`, `strip`, `lstrip`, `rstrip`, `chomp`, `chop`, `to_s` | String |
| 置換 | `sub(s, pat, repl)`, `gsub(...)` | String。`sub!`, `gsub!` はその場で |
| 詰め物と文字の置き換え | `ljust(s, n, [pad])`, `rjust`, `center` · `tr(s, a, b)`, `delete(s, chars)`, `squeeze(s, [chars])`, `succ`, `next` | String |
| 問い合わせ | `empty?`, `include?(s, t)`, `start_with?`, `end_with?`, `match?(s, re)`, `casecmp?` | true/false |
| 分割 | `chars`, `lines`, `bytes`, `split(s, [sep, [limit]])`, `scan(s, re)` | Array |
| 位置 | `index(s, t, [start])`, `rindex`, `byteindex` | Integer か nil |
| 正規表現の一致 | `match(s, re, [pos])` | MatchData か nil |
| 他の型へ | `ord` · `hex` · `oct` · `to_sym`, `intern` | Integer · Symbol |
| バイト列と変換 | `byteslice(s, i, [n])`, `b`, `force_encoding(s, enc)`, `encode`, `encoding`, `valid_encoding?`, `unpack(s, fmt)`, `unpack1` | Ruby と同じ |
| 繰り返し | `each_line(s) { }`, `each_char(s) { }`, `each_byte` | s（ブロック） |

- **置換の repl。** `sub`、`gsub` の repl は、String（`\1` 可）、Hash（一致 => 置換）、またはブロック `{ |m| ... }` です。

## Array

Array は長さが変わる並びです。`Any[1, 2]` で作ります（リテラル `[1, 2]` は Tuple です）。最初に使うのは `Array.push`、`Array.each`、`Array.map` と `Array.select` です。詳細は [Array](ref/Array.md)。

```ruby
xs = Any[3, 1, 2]
Array.push(xs, 5)
p(xs)                                      # => [3, 1, 2, 5]
p(Array.map(xs) { |x| x * 2 })             # => [6, 2, 4, 10]
p(Array.select(xs) { |x| x > 1 })          # => [3, 2, 5]
p(Array.sort(xs))                          # => [1, 2, 3, 5]
p(Array.reduce(xs, 0) { |acc, x| acc + x })   # => 11
p(Array.first(xs))                         # => 3
p(Array.join(xs, "-"))                     # => "3-1-2-5"
p(Array.tally(Any["a", "b", "a"]))       # => {"a" => 2, "b" => 1}
```

| 目的 | 操作 | 結果 |
|---|---|---|
| 作る | `Any[...]` · `Array.new(n)`, `Array.new(n, v)`, `Array.new(n) { \|i\| }` | 新しい Array |
| 長さと問い合わせ | `length`, `size` · `empty?`, `include?(a, x)` | Integer · true/false |
| 足す・消す（その場で） | `push(a, *xs)`, `append`, `unshift`, `concat(a, b)`, `insert(a, i, *xs)`, `delete_if`, `clear` | a |
| 1 要素を取る | `first`, `last`, `min`, `max`, `pop`, `shift`, `at(a, i)`, `sample`, `delete(a, x)`, `delete_at(a, i)` | 要素、または nil |
| 部分を取る | `first(a, n)`, `last(a, n)`, `shift(a, n)`, `take`, `drop`, `slice(a, i, n)` | 新しい Array |
| 無ければ失敗 | `fetch(a, i, [default])` | 要素、既定値、または `IndexError` |
| 文字列に | `join(a, [sep])` | String |
| 合計 | `sum(a, [init])` | 和（下記） |
| 並べ替えなど | `reverse`, `sort`, `sort_by`, `uniq`, `compact`, `flatten`, `rotate`, `shuffle`, `dup` | 新しい Array |
| 繰り返し | `each`, `each_with_index`, `each_slice(a, n)`, `each_cons(a, n)`, `cycle` | a（ブロック） |
| 写像と選別 | `map`, `flat_map`, `select`, `filter`, `reject`, `partition`, `group_by`, `tally`, `to_h`, `zip`, `product` | 新しい Array / Hash / Tuple |
| 判定と数え上げ | `any?`, `all?`, `none?`, `count` | true/false · Integer（ブロックは省略可） |
| 畳み込み | `reduce(a, init) { }`, `inject`, `each_with_object(a, memo) { }` | 累積値 |
| 探す | `find`, `detect`, `min_by`, `max_by`, `index(a, x)`, `find_index`, `assoc`, `rassoc` | 要素か nil · Integer か nil |
| 書き換え（その場で） | `map!`, `select!`, `reject!`, `sort!`, `uniq!`, `compact!`, `flatten!`, `reverse!`, `slice!`, `fill`, `replace` | a |
| バイト列に | `pack(a, fmt)` | String |

- **`sum`。** 要素は数、または `Arithmetic` を include する型です。空なら `init`（既定 0）です。
- **ブロック無しの繰り返し。** `each_slice` などをブロック無しで呼ぶと Array を返します。
- **その場の書き換え。** `map!` などは要素型を変えない写像に使います。

## Enum

Enum は Ruby の Enumerable を短い名前にした module で、プログラムを読む前に読まれる prelude（`sakelib/prelude.sake`）が定義します。`Enum.map(x) { }` などは第 1 引数の型でディスパッチし、Array・Hash・Set・Range は自分の操作で答えます（`Enum.map(xs)` は xs が Array なら `Array.map(xs)`）。自分のクラスは `include Enum` と `def each(c) = ... yield(v) ...` を書けば、残りの関数（`map`、`select`、`reject`、`find`、`reduce`、`sum`、`count`、`include?`、`any?`/`all?`/`none?`/`one?`、`min_by`/`max_by`、`sort_by`、`to_a`、`first`、`take`/`drop`、`group_by`、`partition`、`each_with_object`、`compact`、`filter_map`、`flat_map`）が `each` の上に書かれているので全部使えます。詳細は [Enum](ref/Enum.md)。

```ruby
p(Enum.map(Any[3, 1, 2]) { |v| v * 10 })        # => [30, 10, 20]
p(Enum.map(Hash.of(a: 1, b: 2)) { |k, v| "#{k}=#{v}" })   # => ["a=1", "b=2"]
p(Enum.count(1..4) { |v| v > 2 })                 # => 2

class Deck
  include Enum
  attr_reader cards
  def each(d) = Array.each(@cards) { |c| yield(c) }
end
d = Deck.new(Any["A", "K", "Q"])
p(Deck.select(d) { |c| c < "K" })                  # => ["A"]
p(Enum.first(d), Deck.count(d))                   # => "A"
                                                  # => 3
```

Tuple は Enum を include しません。長さと位置ごとの型が決まっているので、添字と分解で扱います。

## Tuple, Range

Tuple は長さと各位置の型が決まった並びで、リテラル `[1, "a"]` が作ります。Range は 2 つの端の組で、`1..5`、`1...5`、終端の無い `1..` があります。Tuple の操作は少なく、`Tuple.to_a` で Array にして扱うのが普通です。Range は `Range.each` で数を数え、`Range.to_a` と `Range.include?` をよく使います。詳細は [Tuple](ref/Tuple.md)、[Range](ref/Range.md)。

```ruby
t = [1, "a"]
p(Tuple.size(t))                 # => 2
p(Tuple.to_a(t))                 # => [1, "a"]
p(Tuple.max([3, 7, 5]))          # => 7
p(Range.to_a(1..5))              # => [1, 2, 3, 4, 5]
p(Range.sum(1..5))               # => 15
p(Range.include?(1...5, 5))      # => false
p(Range.map(1..3) { |i| i * i })    # => [1, 4, 9]
p(Range.first(1.., 3))           # => [1, 2, 3]
```

| 操作 | 結果 |
|---|---|
| `Tuple.size`, `length` · `to_a` · `max`, `min` · `minmax` | Integer · Array · 要素（nil にならない） · `[min, max]` |
| `Range.each`, `each_with_index`, `step(r, n)` | r（ブロック） |
| `to_a`, `map`, `select`, `filter`, `reject`, `zip` | Array |
| `reduce`, `inject` · `sum` · `size` · `count` | 累積値 · Integer |
| `any?`, `all?`, `none?` · `find`, `detect` · `include?`, `cover?`, `member?`, `exclude_end?` | true/false · 要素か nil · true/false |
| `first`, `last`, `min`, `max`, `begin`, `end` | 要素か nil（`first(r, n)`、`last(r, n)` は Array） |

## Hash, Set

Hash はキーから値への対応で、`Hash.of("a" => 1)` か `Hash.new(default)` で作ります（`{a: 1}` は Record です）。Set は重複の無い要素の集まりで、`Set.of(1, 2)` で作ります。最初に使うのは添字 `h[k]` と `h[k] = v`、`Hash.each`、`Hash.fetch`、そして `Set.add` と `Set.include?` です。詳細は [Hash](ref/Hash.md)、[Set](ref/Set.md)。

```ruby
h = Hash.of("a" => 1)
h["b"] = 2
p(h)                                       # => {"a" => 1, "b" => 2}
p(h["c"])                                  # => nil
p(Hash.fetch(h, "a"))                      # => 1
p(Hash.map(h) { |k, v| [k, v * 10] })      # => [["a", 10], ["b", 20]]
counts = Hash.new(0)
counts["x"] += 1
p(counts)                                  # => {"x" => 1}
s = Set.of(1, 2)
Set.add(s, 2)
p(s)                                       # => Set[1, 2]
p(Set.include?(s, 2))                      # => true
p(Set.union(s, Set.of(9)))                    # => Set[1, 2, 9]
```

| 目的 | 操作 | 結果 |
|---|---|---|
| 作る | `Hash.of(k => v, ...)` · `Hash.new([default])` · `Set.of(...)` | 新しい Hash · Set |
| 長さと問い合わせ | `length`, `size`, `empty?`, `key?`, `has_key?`, `include?`, `member?`, `value?` | Integer · true/false |
| 1 つを取る | `fetch(h, k, [default])` · `dig(h, k)` · `delete(h, k)` · `key(h, v)` | 値 · 値か nil · 消した値か nil · キーか nil |
| 書き換え（その場で） | `store(h, k, v)`, `merge!`, `update`, `clear`, `transform_values!`, `transform_keys!`, `select!`, `reject!`, `compact!` | h |
| 新しい Hash | `merge(a, b)`, `invert`, `select`, `filter`, `reject`, `transform_values`, `transform_keys`, `compact`, `slice`, `except` | 新しい Hash |
| Array に | `keys` · `values` · `to_a` · `map` · `sort_by` · `group_by` · `partition` | Array |
| 繰り返し | `each`, `each_pair`, `each_key`, `each_value` | h（ブロック） |
| 判定と探索 | `any?`, `all?`, `none?`, `count`, `sum`, `find`, `detect`, `min_by`, `max_by` | ブロック付き |
| Set の書き換え（その場で） | `Set.add(s, x)`, `add?`, `delete`, `merge`, `subtract`, `clear` | s |
| Set から Array へ | `to_a`, `each`, `map`, `select`, `filter`, `reject` | Array |
| 集合演算 | `union`, `intersection`, `difference`, `\|`, `&`, `-` · `subset?`, `superset?`, `disjoint?`, `intersect?` | 新しい Set · true/false |

## Regexp, MatchData, Symbol, Time, Math

Regexp は正規表現で、リテラル `/\d+/` が作ります。一致の結果が MatchData で、一致しなければ nil です。Symbol は名前そのものの値（`:name`）、Time は 1 つの時刻、Math は初等関数の集まりです。最初に使うのは `Regexp.match` と `m[1]`、`String.scan`、`Time.now`、`Math.sqrt` です。詳細は [Regexp](ref/Regexp.md)、[MatchData](ref/MatchData.md)、[Symbol](ref/Symbol.md)、[Time](ref/Time.md)、[Math](ref/Math.md)。

```ruby
m = Regexp.match(/(\d+)-(\d+)/, "tel 03-1234")
if m
  p(m[1])                        # => "03"
  p(MatchData.captures(m))       # => ["03", "1234"]
end
p(String.scan("a1 b22", /\d+/))  # => ["1", "22"]
p(Symbol.to_s(:name))            # => "name"
t = Time.at(0, in: "UTC")
p(Time.year(t))                  # => 1970
p(Time.strftime(t, "%Y-%m-%d"))  # => "1970-01-01"
p(Math.sqrt(16))                 # => 4.0
```

| 操作 | 結果 |
|---|---|
| `Regexp.new(s, flags = "")` · `escape(s)` · `source(r)` · `match(r, s, [pos])` · `match?` | Regexp · String · String · MatchData か nil · true/false（flags は `imx` の文字） |
| `MatchData.captures` · `named_captures` · `names` · `to_a` · `to_s`, `pre_match`, `post_match` · `begin(m, i)`, `end(m, i)` | Array · Hash · Array · Array · String · Integer |
| `Symbol.to_s` · `length`, `size` | String · Integer |
| `Time.now` · `at(seconds, [in:])` · `new(y, [m, d, h, min, s, zone])` · `utc(t)`, `getutc` · `getlocal(t, [zone])`, `localtime` | Time |
| `year`, `month`, `day`, `hour`, `min`, `sec`, `wday`, `yday`, `to_i`, `utc_offset` · `to_f` · `to_s`, `strftime(t, fmt)` · `zone` · `utc?` | Integer · Float · String · String か nil · true/false |
| `Math.sqrt`, `cbrt`, `sin`, `cos`, `tan`, `atan`, `exp`, `log`, `log2`, `log10`, `atan2(y, x)`, `hypot(x, y)` | Float |

- **`Symbol.to_proc` は無い。** ブロックは値ではないので、`&:name` は書けません（[関数とブロック](04-functions.md)）。

## Rational, Complex

Rational は常に既約の有理数（`1/3r`）、Complex は複素数（`1 + 2i`）です。どちらも算術演算子がそのまま使え、`Rational(1, 3)` と `Complex(1, 2)` は Kernel の操作です。詳細は [Rational](ref/Rational.md)、[Complex](ref/Complex.md)。

```ruby
r = Rational(1, 3)
p(r + 1/6r)                      # => (1/2)
p(Rational.numerator(r))         # => 1
p(Rational.to_f(r))              # => 0.3333333333333333
c = Complex(1, 2)
p(c * c)                         # => (-3+4i)
p(Complex.abs(Complex(3, 4)))    # => 5.0
p(Integer.fdiv(7, 2))            # => 3.5
```

| 操作 | 結果 |
|---|---|
| `Rational(a, [b])` · `Integer.to_r` · `Float.to_r` · `Float.rationalize` | Rational |
| `Rational.numerator`, `denominator`, `to_i`, `floor`, `ceil`, `round`, `truncate` · `to_f` · `abs` | Integer · Float · Rational |
| `Complex(re, [im])` · `Complex.real`, `imaginary` · `abs`, `arg` · `conjugate` · `rectangular` · `polar` | Complex · 実数 · Float · Complex · `[re, im]` · `[abs, arg]` |
| `Integer.fdiv(a, b)` | Float |

## File, Dir, IO, ENV, Process

File と Dir はパス（String）でファイルとディレクトリを扱う操作の集まりで、値はありません。IO は開いたファイルと標準ストリーム（`IO.stdin`、`IO.stdout`、`IO.stderr`）の型です。ENV は環境変数、Process はプロセスの情報と時計、Open3 は子プロセス、Zlib は圧縮です。最初に使うのは `File.read`、`File.write`、`File.open(path) { |io| }`、`Dir.glob` です。詳細は [File](ref/File.md)、[Dir](ref/Dir.md)、[IO](ref/IO.md)、[ENV](ref/ENV.md)、[Process](ref/Process.md)、[Open3](ref/Open3.md)、[Zlib](ref/Zlib.md)。

```ruby
dir = Dir.mktmpdir
path = File.join(dir, "notes.txt")
p(File.write(path, "one\ntwo\n"))          # => 8
p(File.readlines(path))                    # => ["one\n", "two\n"]
File.open(path, "a") { |io| IO.puts(io, "three") }
p(Array.length(File.readlines(path)))      # => 3
p(Dir.children(dir))                       # => ["notes.txt"]
p(ENV.fetch("NO_SUCH_VAR", "default"))     # => "default"
out, status = Open3.capture2("echo", "hi")
p(out)                                     # => "hi\n"
File.delete(path)
Dir.rmdir(dir)
```

| 操作 | 結果 |
|---|---|
| `File.read(path)` · `readlines` · `write(path, s)` · `exist?`, `file?`, `directory?`, `symlink?`, `zero?`, `empty?`, `readable?`, `writable?`, `executable?`, `absolute_path?` | String · Array · Integer · true/false |
| `File.size`, `mtime`, `atime`, `ftype` · `rename`, `symlink`, `link`, `readlink`, `unlink`, `delete`, `chmod`, `utime` | Integer · Time · String · ... |
| `File.basename(p, [suffix])`, `dirname(p, [levels])`, `extname`, `join(*parts)`, `expand_path(p, [dir])`, `absolute_path`, `realpath` · `split(p)` | String · `[dir, base]` |
| `File.open(path, mode = "r", [perm])` · `File.open(...) { \|io\| }` | IO · ブロックの値（閉じる） |
| `Dir.children`, `entries` · `glob(pat, [base:])` · `each_child(path) { }` · `exist?`, `empty?` · `mkdir(path, [mode])`, `rmdir` · `pwd`, `home`, `tmpdir` · `mktmpdir([prefix, [dir]])` | Array of String · ... |
| `IO.puts(io, ...)`, `print`, `write(io, s)` · `gets(io)`, `read(io, [n])`, `readlines`, `getc` · `each_line(io) { }` · `eof?`, `closed?`, `tty?` · `flush`, `close` · `seek(io, off, [whence])`, `pos`, `rewind`, `truncate`, `size` | nil · String か nil · ... |
| `ENV.fetch(name, [default])`, `get(name)`, `set(name, v)`, `key?`, `delete`, `to_h`, `keys` | String · ... |
| `Process.clock_gettime(Process.CLOCK_MONOTONIC)`, `pid` | Float · Integer |
| `Open3.capture2(cmd, ...)`, `capture2e`, `capture3` | `[out, status]` などの Tuple |
| `Zlib.inflate`, `deflate`, `gzip`, `gunzip` | String |

- **閉じた IO。** 閉じた IO、またはその向きに開いていない IO の読み書きは `IOError` です。
- **stderr の順序。** `IO.stderr` への書き込みは stdout を先に flush するので、行の順序が保たれます。

## スレッドとソケット

Thread はブロックを並行に走らせ、Mutex が排他、Queue がスレッド間の受け渡しを担います。TCPServer と Socket は TCP の待ち受けと接続です。最初に使うのは `Thread.new { }` と `Thread.value`、`Mutex.synchronize`、`Queue.push`/`pop` です。詳細は [Thread](ref/Thread.md)、[Mutex](ref/Mutex.md)、[Queue](ref/Queue.md)、[TCPServer](ref/TCPServer.md)、[Socket](ref/Socket.md)。

```ruby
count = 0
m = Mutex.new
ts = Array.map(Any[1, 2, 3]) { |w| Thread.new { Mutex.synchronize(m) { count += w }; w * 10 } }
p(Array.map(ts) { |t| Thread.value(t) })   # => [10, 20, 30]
p(count)                                   # => 6
q = Queue.new
producer = Thread.new { Range.each(1..3) { |i| Queue.push(q, i) }; Queue.close(q) }
got = Any[]
loop do
  x = Queue.pop(q)
  break if x == nil
  Array.push(got, x)
end
Thread.join(producer)
p(got)                                     # => [1, 2, 3]
```

| 操作 | 結果 |
|---|---|
| `Thread.new { ... }` · `Thread.value(t)` · `join(t, [limit])` · `alive?(t)` · `current` · `kill(t)` · `raise(t, msg)` | Thread · ブロックの値（待つ。スレッドのエラーはここで上がる）· t か nil · true/false |
| `Mutex.new` · `synchronize(m) { }` · `lock`, `unlock`, `try_lock`, `locked?`, `owned?` | Mutex · ブロックの値 |
| `Queue.new` · `push(q, x)` · `pop(q, [timeout])` · `close`, `size`, `empty?`, `closed?` | Queue · q · 最古の要素（待つ。閉じて空なら nil） |
| `TCPServer.new(host, port)` · `accept(s)` · `port(s)` · `close(s)` | TCPServer（port 0 は空きを選ぶ）· Socket（待つ）· Integer · nil |
| `Socket.connect(host, port, [timeout])` · `connect_ssl(host, port, [timeout])` · `set_timeout(s, secs)` | Socket（`connect_ssl` は TLS、相手を検証） |
| `Socket.gets(s)` · `read(s, n)` · `write(s, str)` · `close_write(s)` · `close(s)` | String か nil · String か nil · Integer · nil · nil |

- **スレッドの変数。** ブロックは周りの変数を共有します。スレッドでは、`Thread.new` を囲むブロックの変数（引数とローカル）とスレッドブロック自身の変数は開始時に複製され、関数の変数は共有のままです。上の例の `Array.map(xs) { |w| Thread.new { ... w ... } }` は各スレッドに自分の `w` を与え、共有カウンタ `count` は `Mutex.synchronize` の中で更新する関数の変数です。
- **スレッドブロックを抜ける。** `Thread.new` のブロックからの `break` と `return`（その中のブロックの `return` も）は静的エラーです。ブロックは呼び出しが戻った後で走るからです。`next v` は `v` で終えます。
- **エラー。** スレッドの中のエラーは `Thread.value` か `Thread.join` で上がります。join されないスレッドは失敗しても黙って終わり、メインが終わればすべてのスレッドが止まります。
- **検査。** 型推論はスレッドのブロックを `Thread.new` で 1 度走らせます。その値が `Thread.value` の型、Queue の要素型は push されたものの和です（`Queue.pop` は nil を加える）。交互実行は解析せず、各操作が実行時に引数を検査します。

## 型付き Array

`Integer[...]`、`Float[...]`、`Rational[...]`、`Complex[...]`、`String[...]`、`Symbol[...]`、`Tuple[...]`、および各クラス `D` の `D[...]` は、要素型がその型の Array を作ります（[値と型](03-values.md)）。書き込みは要素型と照合され、合わない値は静的には `type` の問題、実行時には `TypeError` です。

```ruby
xs = Integer[1, 2]
Array.push(xs, 3)
p(xs)                            # => [1, 2, 3]
Point = Struct.new(:x, :y)
pts = Point[Point.new(0, 0)]
p(Array.length(pts))             # => 1
p(String[])                      # => []
```

```ruby error
xs = Integer[1, 2]
Array.push(xs, "a")              # !> Array.push: an element must be Integer, but is String [type]
```

# ライブラリ（sakelib）

処理系には、Ruby の標準添付ライブラリと主な gem を Sake で書き直したライブラリ群 `sakelib/` が付属します。この章では、ライブラリの読み込み方、何が移植されているか、テスト枠組み minitest、そして各移植がどう検査されているかを述べます。個々のライブラリの API は `sakelib/notes/NAME.md` にあり、この章はその一覧です。

## 読み込みと名前

ライブラリは `require "json"` のように読みます。ライブラリの名前も、その中の操作の名前も Ruby のものに従うので、Ruby で知っている名前がそのまま使えます。違うのは呼び出しの形だけです。

- **探す場所。** `require "name"` は、まず require するファイルと同じディレクトリの `name.sake` を探します。無ければ処理系に付属する `sakelib/name.sake` を読みます。隣にある `name.sake` が require している自分自身か、ライブラリでないプログラムのときも sakelib のほうを読みます。どのディレクトリから実行しても `require "json"` は同じ `sakelib/json.sake` です。
- **`/` を含む名前。** Ruby の `net/http`、`open-uri` は `net_http`、`open_uri` と書きます。
- **モジュール関数は Ruby のまま。** `JSON.parse(s)`、`Base64.encode64(s)` は Ruby と同じ字面です。
- **インスタンスメソッドは主語が先。** Ruby の `ss.scan(/\w+/)` は `StringScanner.scan(ss, /\w+/)` です（[プログラムの構造と名前解決](02-program.md)）。
- **入れ子の名前は Ruby のまま。** 名前空間は入れ子にできるので（[プログラムの構造と名前解決](02-program.md)）、`Net::HTTP`、`Concurrent::Future`、`JSON::ParserError`、`Benchmark::Tms` は Ruby と同じ字面です: `Net::HTTP.get(http, path)`、`rescue JSON::ParserError`。外側が組み込み型の名前だけは作れません（`Enumerable` が無いので、ActiveSupport の `Enumerable::SoleItemExpectedError` はトップレベルの `SoleItemExpectedError` です）。対応表は各ライブラリの notes にあります。

```ruby
require "base64"
require "strscan"

e = Base64.encode64("hello")
p(e)                                  # => "aGVsbG8=\n"
p(Base64.decode64(e))                 # => "hello"
ss = StringScanner.new("foo bar")
p(StringScanner.scan(ss, /\w+/))      # => "foo"
p(StringScanner.scan(ss, /\w+/))      # => nil
p(ss.StringScanner.scan(/\s+/))       # => " "
```

各ライブラリの注記は `sakelib/notes/NAME.md` にあります。Ruby との違いとその理由、無いもの、そして Ruby の API と Sake の API の対応表です。移植しないライブラリとその理由は `sakelib/notes/not-ported.md` にあります。

## 標準添付ライブラリの移植

Ruby の標準添付ライブラリのうち、Sake で書けるものを移植しています。移植できないものの大半は、`method_missing`・`define_method`・特殊変数・第一級のブロックに依るもので、Sake がわざと持たない機能です。TLS・UDP・端末のように OS や C 実装が要るものは、ライブラリではなく処理系に組み込みます。

```ruby
require "json"

doc = JSON.parse("{\"name\": \"ann\", \"tags\": [\"a\", \"b\"]}")
p(doc)                                # => {"name" => "ann", "tags" => ["a", "b"]}
if doc in Hash
  p(doc["name"])                      # => "ann"
  puts(JSON.generate(doc))            # => {"name":"ann","tags":["a","b"]}
end
```

`JSON.parse` は Hash・Array・String・Integer・Float・true/false・nil のどれかを返すので、添字で読む前に `if doc in Hash` で絞り込みます（[制御構造とパターン](06-control.md)）。絞り込まずに `doc["name"]` と書くと、検査器は「添字できない型かもしれない」と報告します。

| 分野 | ライブラリ |
|---|---|
| データ形式 | json, csv, yaml, toml, ini, base64, digest, zlib, xml, erb, mustache |
| 文字列・解析 | strscan, optparse, getoptlong, shellwords, abbrev, prettyprint, pp, text, diff, terminal_table |
| 数 | bigdecimal, matrix, prime, securerandom, units |
| 時間 | time, date |
| 入出力・OS | fileutils, pathname, find, tempfile, stringio, logger, benchmark |
| ネットワーク | net_http, open_uri, uri, cgi, ipaddr, webrick |
| 並行 | monitor, mutex_m, timeout, observer, event_emitter |
| データ構造 | pqueue, lru_cache, trie, tsort, state_machine, semver |

### 部分的な移植と補足

- **yaml** は Psych の部分集合、**xml** は REXML の部分集合です。
- **digest** は MD5 と SHA を Sake で計算します（遅い）。**zlib** は CRC-32 と Adler-32 のチェックサムだけで、圧縮はありません。
- **net_http** は `Net::HTTP`、`Net::HTTPResponse`、`Net::HTTP::Get` など Ruby の名前のままです。https は組み込みの `Socket.connect_ssl` を使います。
- **timeout** はブロックを別の Thread で走らせ、時間が来たら組み込みの `Thread.raise` で本当に止めます。
- **pp** は組み込みの `pp`（1 行）とは別に、幅で折り返す PP です。

### 組み込みにあるので require しないもの

Ruby では require するが Sake では組み込みの操作になっているものがあります。`require "tmpdir"` は「読めるファイルが無い」という静的エラーになります。

| Ruby の require | Sake の組み込み |
|---|---|
| `tmpdir` | `Dir.mktmpdir`、`Dir.tmpdir`（`Dir.tmpdir` は tempfile が足す） |
| `open3` | `Open3.capture2`、`capture2e`、`capture3`、`Kernel.system` |
| `set` | `Set.of(...)`、`Set.add` ...（[値と型](03-values.md)） |
| `socket` | `TCPServer`、`Socket`（TCP のみ） |

### gem に倣った小さなライブラリ

上の表のうち toml（toml-rb）、ini（inifile）、mustache、units（ruby-units）、text、diff（diff-lcs）、terminal_table、event_emitter（Node の EventEmitter）、pqueue、lru_cache（lru_redux）、trie、state_machine（AASM 風）、semver は Ruby の標準添付ではなく、よく使われる gem や他言語のライブラリに倣って書いたものです。どれに倣ったかは各 notes の冒頭にあります。

### 移植しないものの代わり

- **singleton** の代わりは `once { T.new(...) }` です（[関数とブロック](04-functions.md)）。
- **forwardable / delegate** の代わりは、委譲する操作を 1 つずつ書くことです。
- **ostruct** の代わりは Record `{a: 1}` か Hash です。

## gem の移植

よく使われる gem も、Sake で書ける範囲で移植しています。各移植は gem の名前を Sake で書ける限り保ちます（`ActiveSupport::Inflector.pluralize(s)`、`Redis.get(r, k)`）。

| 分野 | ライブラリ |
|---|---|
| 端末・CLI | colorize, ruby_progressbar, highline, thor, awesome_print |
| ActiveSupport | active_support_inflector, active_support_core_ext, active_support_number_helper |
| テキスト | kramdown, liquid, i18n, faker |
| Web | rack, rackup, webrick, httparty |
| データ | redis, dotenv, money, rubyzip, chronic, jwt |
| 並行・テスト | concurrent_ruby, rspec, minitest |

### 補足

- **active_support_core_ext** は `Blank`、`StringExt`、`ArrayExt`、`HashExt` の各 module と、クラス `ActiveSupport::Duration` です。
- **kramdown** は GFM 方言、**redis** は RESP2 のクライアント、**jwt** は HS256/384/512 です。
- **concurrent_ruby** は `Concurrent::Future`、`Concurrent::Promise`、`Concurrent::Atom`、`Concurrent::Map`、`Concurrent::Semaphore` などです。
- **rspec** は minitest と同じ形で、例を名乗って書きます: `RSpec.expect(ex, x).To.eq(y)`。

### 落とした機能

落とした機能とその理由は `sakelib/notes/not-ported.md` の表にあります。主なものは次の 3 つです。

- **保持するブロック。** `then(rescuer) {}` やコールバックの登録。ブロックは第二級なので格納できません（[関数とブロック](04-functions.md)）。
- **反射。** `constantize`、`send`、`define_method`。名前からの呼び出しはありません。
- **クラスを値で渡す API。** `expect(x).to be_a(T)`。型は値ではないので、`x in T` か型ごとの関数にします。

## minitest

`sakelib/minitest.sake` は、Sake で書いたプログラムのための Ruby の Minitest 風のテスト枠組みです。Sake 自身のテストスイート（`test/sake/*_test.sake`）もこれで書かれています。

### テストの書き方

Sake には反射が無いので、テストは名前で見つけるメソッドではなく、`Minitest.test` に渡すブロックです。各アサーションは、属するテスト（ブロックの引数 `t`）を第 1 引数で名乗ります。Sake のすべての操作が主語を名乗るのと同じです。

```ruby
require "minitest"

suite = Minitest.suite("strings")
Minitest.test(suite, "upcase and split") do |t|
  Minitest.assert_equal(t, "ABC", String.upcase("abc"))
  Minitest.assert_equal(t, Any["a", "b"], String.split("a,b", ","))
  Minitest.assert(t, String.empty?(""))
end
Minitest.run(suite)      # 報告を印字。失敗があれば終了コード 1
```

```
# Running strings:

.

Finished in 0.026718s

1 runs, 3 assertions, 0 failures, 0 errors
```

- **テストはその場で走ります。** `Minitest.test` はブロックをすぐ走らせて結果を記録します。テストは定義順に走ります。
- **`Minitest.run(suite)`** は報告を印字し、失敗かエラーがあれば終了コード 1 で終わります。`Minitest.report(suite)` は印字だけして、全部通ったかを true / false で返します。

### アサーション

`Minitest` の関数で、どれも第 1 引数がテスト `t`、最後に省略できるメッセージを取ります。

| 関数 | 検査 |
|---|---|
| `assert(t, cond)`, `refute(t, cond)` | 真 / 偽 |
| `assert_equal(t, expected, actual)`, `refute_equal` | `==` |
| `assert_nil(t, x)`, `refute_nil` | nil |
| `assert_in_delta(t, expected, actual, delta = 0.001)` | 差が delta 以内 |
| `assert_includes(t, collection, x)`, `refute_includes` | 要素を含む |
| `assert_empty(t, collection)`, `refute_empty` | 空 |
| `assert_match(t, pattern, s)` | Regexp に一致 |
| `assert_raises(t) { ... }` | ブロックが例外を投げる。例外のメッセージを返す |

`assert_output` はありません。Sake のプログラムは自分の出力を捕まえられないので、値を印字して比べます。

### 失敗とエラー

失敗したアサーションは `Minitest::Assertion` を投げ、失敗（F）として記録されます。他の例外はエラー（E）として記録されます。Ruby の Minitest と同じです。

```ruby
require "minitest"

suite = Minitest.suite("numbers")
Minitest.test(suite, "integer division floors") do |t|
  Minitest.assert_equal(t, 3, 7 / 2)
end
Minitest.test(suite, "divides by zero") do |t|
  Minitest.assert_equal(t, 0, 1 / 0)
end
Minitest.test(suite, "wrong expectation") do |t|
  Minitest.assert_equal(t, 4, 2 + 3)
end
Minitest.run(suite)      # 終了コード 1
```

```
# Running numbers:

.EF

Finished in 0.035481s

  1) Error:
divides by zero
divided by 0

  2) Failure:
wrong expectation
expected 4, got 5

3 runs, 2 assertions, 1 failures, 1 errors
```

## テスト

ライブラリの各移植には Ruby の双子があります。同じプログラムを Sake のライブラリで書いた `test/sakelib/NAME.sake` と、Ruby のライブラリで書いた `test/sakelib/NAME.rb` で、両方が同じ出力を印字しなければなりません。移植の正しさの定義はこの「同じ出力」です。

```ruby
# test/sakelib/shellwords.sake の形
require "shellwords"
p(Shellwords.split("a 'b c' d"))      # => ["a", "b c", "d"]
p(Shellwords.escape("it's"))          # => "it\\'s"
```

```ruby
# 双子の shellwords.rb。Ruby で同じ 2 行を印字する
require "shellwords"
p(Shellwords.split("a 'b c' d"))
p(Shellwords.escape("it's"))
```

- **走らせ方。** `ruby test/test_sakelib.rb` が、各 `.sake` を `bin/sake --strict`（レベル 2）で、各 `.rb` を Ruby で `test/sakelib/` の中で走らせ、出力を比べます。
- **gem が無いとき。** 手元に無い gem の双子は、gem と同じ名前と出力を持つ素の Ruby の参照実装 `test/sakelib/ref/NAME.rb` で走らせます。
- **notes。** 双子が一致しない箇所、Ruby と違えた箇所は `sakelib/notes/NAME.md` に書きます。

# 組み込みリファレンス

組み込みの型とモジュールごとに 1 章ずつ、その名前空間の**すべての操作**を載せます。章の見出しは操作の名前で、別名は 1 つの節にまとめています（`find, detect`）。各節の最初の行は正確な署名です:

- `Array.first(x, [Integer])`: `x` はその名前空間の型の値（主語）、`[T]` は省略できる引数、`*T` は任意個の引数、`[k: T]` はキーワード、` { }` は必須のブロック、` [{ }]` は省略できるブロック。
- `Integer[*Any]` のような `T[...]` は、T の値の **Array**（型付き Array）を作る構築子です。

本文では、操作が何をして何を返すか、引数の意味、結果が **nil** になる場合とそれを検査器がどの厳格レベルで報告するか、投げる**例外**、検査器が静的に弾くもの、主語を書き換えるか新しい値を返すか、Ruby の同名メソッドとの違い、を順に述べます。例の `# => 値` は実際の出力で、`ruby tools/check_reference.rb` がすべての例を `--strict=2` で走らせて照合し、署名と操作の網羅も確かめています（`ruby error` と書いた例は、弾かれる・失敗することを確かめたもの）。

章の順は、Kernel と例外、数、文字列と正規表現、並びと写像、時刻、入出力と OS、スレッドとソケットです。演算子（`+`、`<`、`[]`）の規則は[演算子と添字](05-operators.md)に、各型の値の性質は[値と型](03-values.md)にあります。

# Kernel

Kernel はプログラム全体から名前だけで呼べる操作の集まりです。`puts(x)`、`Integer(s)`、`loop { }` のように書き、`Kernel.puts(x)` と書く必要はありません（書いても動きます。名前の解決は、今の名前空間、トップレベルの関数、Kernel の順です。[関数](../04-functions.md)）。他の名前空間の操作と同じく、引数の型は静的に検査され、合わない型は `type` の問題です。

ここにあるのは入出力（`puts`、`print`、`p`、`pp`、`format`、`gets`、`warn`）、厳密な数値変換（`Integer`、`Float`、`Rational`、`Complex`）、値の表示（`to_s`、`inspect`）と複製（`dup`、`equal?`）、制御（`loop`、`block_given?`、`once`）、乱数と時間（`rand`、`srand`、`sleep`）、プロセス（`exit`、`at_exit`、`system`、`ARGV`、`PROGRAM_NAME`）です。`raise` は操作ではなく構文で、[例外とエラー](../08-exceptions.md)にあります。`Math.PI` や `Float.INFINITY` も操作として読みますが、それぞれの名前空間の章にあります（Sake に値の定数は無く、名前の付いた値は `once` で作ります）。

## Kernel[]

`Kernel[*Any]`

何でも入る Array を作ります。どの型も Kernel を include しているので、モジュールの `M[...]`（M を include した型の Array）の規則により、この Array はどんな値も受けます。prelude が `Any = Kernel` と名付けていて、`Any[...]` と書きます。要素の型は何でもよく、混ぜてもよく、以後どんな値でも追加できます（検査器は追加された値の型を要素型の和に加えます）。空の Array は `Any[]`。リテラル `[1, 2]` は Tuple なので、伸ばせる並びは `Any[...]` と書きます。型付き Array は `Integer[1, 2]` のように型の名前で作り、`Array[...]` は Array の Array です。

```ruby
xs = Any[1, "a"]
Array.push(xs, :sym)
p(xs)                          # => [1, "a", :sym]
e = Any[]
Array.push(e, 1)
p(e)                           # => [1]
p([1, 2] == Any[1, 2])         # => false
```

```ruby error
xs = [1, 2]
Array.push(xs, 3)              # !> `[...]` is a Tuple with a fixed length; for a growable Array, write `Any[...]`
```

## puts

`Kernel.puts(*Any)`

各引数を 1 行ずつ出力に書き、nil を返します（Ruby の `puts`）。String はそのまま（末尾に改行が無ければ足す）、nil は空行、他の値は `to_s` の形です。Array と Tuple は要素を 1 行ずつ、入れ子も平らにして書きます（空の Array は空行）。引数が無ければ空行です。クラスのインスタンスは型自身の `to_s(x)` があればそれで、無ければ `p` と同じ `#<struct ...>` の形で書きます（[to_s](#to_s)）。

```ruby
puts("a", 1, :sym)
# => a
# => 1
# => sym
puts(Any[1, [2, 3]])
# => 1
# => 2
# => 3
puts(Hash.of("k" => 1), 1..3)
# => {"k" => 1}
# => 1..3
```

## print

`Kernel.print(*Any)`

各引数を `to_s` の形で改行を挟まずに書き、nil を返します（Ruby の `print`）。Array と Tuple は `[1, 2]` の形（`puts` のように 1 行ずつにはなりません）、nil は空文字列です。

```ruby
print("a", 1, nil, "\n")        # => a1
print(Any[1, 2], [3, 4], "\n") # => [1, 2][3, 4]
```

## p

`Kernel.p(*Any)`

各引数を `inspect` の形で 1 行ずつ書きます（Ruby の `p`）。String は引用符付き、Symbol は `:sym`、クラスのインスタンスは `#<struct Point x=1, y=2>`、例外値は `#<KeyError: msg>` です。戻り値は Ruby と同じく、引数が 1 つならその値、複数なら引数の Tuple、無ければ nil（検査器もそう見ます）。型自身の `inspect(x)` を持つ クラスのインスタンスはそれで書きます。

```ruby
x = p(1, "a")
# => 1
# => "a"
p(x)                             # => [1, "a"]
p(p())                           # => nil
Point = Struct.new(:x, :y)
p(Point.new(1, 2))               # => #<struct Point x=1, y=2>
p(Hash.of("a" => 1), Set.of(1), 2r)
# => {"a" => 1}
# => Set[1]
# => (2/1)
```

## pp

`Kernel.pp(Any)`

1 つの値を `p` と同じ形で書き、その値を返します。Ruby の `pp` は長い値を折り返しますが、Sake では `p(x)` と同じです。

```ruby
a = pp(Any[1, {k: 2}])        # => [1, {k: 2}]
p(a)                             # => [1, {k: 2}]
```

## format, sprintf

`Kernel.format(String, *Any)`

`Kernel.sprintf(String, *Any)`

Ruby の `format` と同じ書式で String を作ります: `%d`、`%f`、`%e`、`%g`、`%x`、`%o`、`%b`、`%c`、`%s`、`%p`、`%%` と、幅・精度・`-`・`+`・`0` のフラグ。`%s` は値の `to_s`（クラス自身の `to_s(x)` も使われます）、`%p` は `inspect` です。`%<name>d` と `%{name}` は、Record（`{a: 1}`）か Symbol をキーに持つ Hash（`Hash.of(a: 1)`）を唯一の引数として 1 つ渡します。演算子の形 `fmt % x` も同じです（[String](String.md)）。引数が足りない・多すぎる、数値の指示子に数にならない値を渡す、無いキーを名乗る（`key<a> not found`）、はすべて `ArgumentError` です。

```ruby
p(format("%05.2f|%-4s|%p|%x", 3.14159, :ab, "q", 255))   # => "03.14|ab  |\"q\"|ff"
p(sprintf("%+d %s %s", 3, nil, true))                     # => "+3  true"
p(format("%<a>d-%<b>s", {a: 1, b: "x"}))                  # => "1-x"
p("%<a>05d" % {a: 42})                                    # => "00042"
p(format("%<n>d-%{s}", Hash.of(n: 1, s: "x")))               # => "1-x"
Point = Struct.new(:x, :y)
p(format("%s", Point.new(1, 2)))                          # => "#<struct Point x=1, y=2>"
```

```ruby error
p(format("%d %d", 1))            # !> ArgumentError: Kernel.format: too few arguments
```

```ruby error
p(format("%<a>d", {b: 1}))       # !> ArgumentError: Kernel.format: key<a> not found
```

## gets

`Kernel.gets()`

標準入力から 1 行を読み、末尾の改行を含めた String を返します。入力の終わりでは nil です。戻り値は `String | nil` なので、検査せずに `String.chomp(gets)` と書くと `--strict`（レベル 2）が `nil` の問題として止めます。`if (line = gets)` のように先に調べます。Ruby の `gets` と違い引数（区切り）は取りません。

```ruby
line = gets
p(line)                          # => "3\n"
if (rest = gets)
  p(String.split(String.chomp(rest), " "))   # => ["1", "2"]
end
p(gets)                          # => nil
```

```ruby error
p(String.chomp(gets))            # !> argument 1 may be nil
```

## warn

`Kernel.warn(*Any)`

各引数を `puts` と同じ形でエラー出力（stderr）に書き、nil を返します。引数が無ければ何も書きません。使い方の誤りを報告して `exit` する、という組み合わせが典型です。

```ruby error
warn("usage: prog FILE")         # !> usage: prog FILE
exit(2)
```

## Integer

`Kernel.Integer(String|Integer|Float)`

Ruby の厳密な `Integer()` です。String は 10 進の整数、または `0x`・`0b`・`0o`・`0` 接頭辞付きの整数で、`_` の区切りと前後の空白は許されます。それ以外（`"12abc"`、`""`、`"1e3"`）は `ArgumentError`。Float は切り捨て、Integer はそのままです。`String.to_i` は読めるところまでを黙って読みますが、こちらは全体が整数でなければ失敗します。NaN や Infinity の Float は `FloatDomainError` で（メッセージは値の名前 `NaN`・`Infinity`）、他の例外と同じく rescue できます。

```ruby
p(Integer("42"))                 # => 42
p(Integer(" 0x1f "))             # => 31
p(Integer("1_000"))              # => 1000
p(Integer(3.9))                  # => 3
p(String.to_i("12abc"))          # => 12
```

```ruby error
p(Integer("12abc"))              # !> ArgumentError: Kernel.Integer: invalid value for Integer(): "12abc"
```

```ruby error
p(Integer(Float.NAN))            # !> FloatDomainError: Kernel.Integer: NaN
```

## Float

`Kernel.Float(String|Integer|Float)`

Ruby の厳密な `Float()` です。String は 10 進の実数（`"1e3"`、`"1_0.5"`、前後の空白可）でなければ `ArgumentError`。Integer は Float に、Float はそのままです。

```ruby
p(Float("1.5"))                  # => 1.5
p(Float("1e3"))                  # => 1000.0
p(Float(2))                      # => 2.0
```

```ruby error
p(Float("abc"))                  # !> ArgumentError: Kernel.Float: invalid value for Float(): "abc"
```

## Rational

`Kernel.Rational(Integer|Float|Rational|String, [Integer|Rational])`

Ruby の `Rational(a, b = 1)` です。`a` は Integer、Float、Rational、または `"1/3"`・`"0.75"`・`"3"` の形の String、`b` は Integer か Rational で、`a / b` を既約の Rational にします。Float は `Float.to_r` と同じく正確な値として読むので、`Rational(0.5)` は `(1/2)` ですが、`Rational(0.1)` は `0.1` が実際に表す長い 2 進の分数です（短い `(1/10)` が欲しければ `Float.rationalize`）。読めない String は `ArgumentError`、`b` が 0 なら `ZeroDivisionError`、NaN や Infinity の Float は `FloatDomainError`。

```ruby
p(Rational(3, 6))                # => (1/2)
p(Rational("0.75"))              # => (3/4)
p(Rational("1/3"))               # => (1/3)
p(Rational(1r/2, 1r/4))          # => (2/1)
p(Rational(0.5))                 # => (1/2)
p(Rational(1.5, 1r/2))           # => (3/1)
p(Rational(0.1) == Float.to_r(0.1))   # => true
p(Float.rationalize(0.1))        # => (1/10)
```

```ruby error
p(Rational(1, 0))                # !> ZeroDivisionError: Kernel.Rational: divided by 0
```

## Complex

`Kernel.Complex(Integer|Float|Rational, [Integer|Float|Rational])`

Ruby の `Complex(re, im = 0)` です。実部と虚部はそれぞれ実数で、String は受け付けません（`String.to_c` を使います）。

```ruby
p(Complex(1, 2))                 # => (1+2i)
p(Complex(1.5))                  # => (1.5+0i)
p(Complex(1r, 2.5))              # => ((1/1)+2.5i)
```

## to_s

`Kernel.to_s(Any)`

値を `puts`・文字列補間 `"#{x}"`・`format` の `%s` が使う形の String にします。String はそのまま、nil は `""`、Symbol は名前、数は Ruby の `to_s`、Array・Tuple・Hash・Set・Record・Range は `inspect` と同じ形です。クラスのインスタンスは、その型が `to_s(x)` を定義していればそれを呼び（`include` したモジュールのものでも）、無ければ `#<struct T ...>` です。Ruby の `x.to_s` に相当しますが、Sake では値へのメソッド呼び出しが無いので、どの型の値もこの 1 つの操作で文字列にします。

```ruby
class Temp
  attr_reader celsius
  def to_s(t) = "#{@celsius}C"
end
t = Temp.new(21)
p(to_s(t))                       # => "21C"
puts("now #{t}")                 # => now 21C
p(to_s(nil))                     # => ""
p(to_s(Any[1, "a"]))           # => "[1, \"a\"]"
p(to_s(:sym))                    # => "sym"
```

## inspect

`Kernel.inspect(Any)`

値を `p` が書く形の String にします（Ruby の `x.inspect`）: String は引用符とエスケープ付き、Symbol は `:sym`、nil は `"nil"`、容器は要素を `inspect` した形です。クラスのインスタンスは、その型が `inspect(x)` を定義していればそれ（`include` したモジュールのものでも）、無ければ `#<struct T f=v, ...>`、例外値は `#<E: message>` です。`p`、`pp`、`format` の `%p`、容器の中の要素の表示がこれを使います。

```ruby
module Pretty
  def inspect(v) = "<pretty>"
end
class Box
  include Pretty
  attr_reader n
end
p(inspect("a\n"))                # => "\"a\\n\""
p(inspect(nil))                  # => "nil"
p(inspect(Box.new(1)))           # => "<pretty>"
p(Any[Box.new(1)])             # => [<pretty>]
```

## dup

`Kernel.dup(Any)`

値の浅い複製（Ruby の `obj.dup`）: Array、Tuple、Hash、Set、Record、クラスのインスタンス、String は新しい容器になり、中の要素は同じ値のままです（要素の容器は共有されます）。Integer、Symbol、nil、true/false、Range はそのままの値が返ります。型は元と同じです。その型が `dup(x)` を定義している クラスのインスタンスには、それを呼びます（戻り値はその関数の型）。型の関数の中で要素を複製するときは `Kernel.dup(@items)` と書きます。裸の `dup` は型自身の `dup` に解決されるからです。

```ruby
a = Any[Any[1], Any[2]]
b = dup(a)
Array.push(b, Any[3])
Array.push(b[0], 9)
p(a)                             # => [[1, 9], [2]]
p(b)                             # => [[1, 9], [2], [3]]
class Box
  attr_accessor items
  def dup(b) = Box.new(Kernel.dup(@items))
end
x = Box.new(Any[1])
y = dup(x)
Array.push(Box.items(y), 2)
p(Box.items(x))                  # => [1]
p(Box.items(y))                  # => [1, 2]
```

## equal?

`Kernel.equal?(Any, Any)`

2 つの引数が同じ値（同一のオブジェクト）なら true（Ruby の `a.equal?(b)`）。`==` は中身を比べますが、こちらは同一性です。`dup` の結果は元と `==` ですが `equal?` ではありません。同じ Integer、Symbol、nil、true/false は常に同一です。別々に書いた String リテラルは同一ではありません。

```ruby
a = Any[1]
b = a
p(equal?(a, b))                  # => true
p(a == dup(a))                   # => true
p(equal?(a, dup(a)))             # => false
p(equal?("a", "a"))              # => false
p(equal?(:a, :a))                # => true
```

## loop

`Kernel.loop() { }`

ブロックを `break` まで繰り返します（Ruby の `loop`）。戻り値は `break v` の `v`（裸の `break` は nil）で、検査器にはブロック内のすべての `break` の値の和が見えます。`next` は次の回へ進みます。`break` の無い `loop` は決して返りません（Ruby の `StopIteration` による終了は Sake にはありません）。

```ruby
i = 0
v = loop do
  i += 1
  next if i < 3
  break i * 10
end
p(v)                             # => 30
p(loop { break })                # => nil
```

## block_given?

`Kernel.block_given?()`

今の関数がブロック付きで呼ばれたなら true。`block_given?` を調べる関数は、ブロック無しでも呼べます（調べない関数で `yield` すれば、ブロックは必須です。[関数](../04-functions.md)）。検査器は条件の中の `block_given?` をその呼び出しごとの値に畳むので、ブロック無しの呼び出しで `yield` に届く枝は走りません。トップレベルでは false です。

```ruby
def each_or(x)
  return yield(x) if block_given?
  x
end
p(each_or(1))                    # => 1
p(each_or(1) { |v| v + 10 })     # => 11
p(block_given?)                  # => false
```

## once

`Kernel.once() { }`

ブロックの値を返します。ブロックはプログラム中のその場所が最初に実行されたとき 1 度だけ走り、値はプログラムの終わりまで保たれて、以後の実行（別の呼び出し、別のスレッド）はその同じ値を受け取ります。Sake には値の定数が無いので、表や名前付きの値を 1 度だけ計算する手段です: `def table = once { ... }`。保たれるのは値そのもので、Array なら後から変えられます（Ruby の定数と同じ）。計算中のブロックが自分の `once` にまた届くと `SystemStackError` でプログラムが止まります（rescue できません）。

```ruby
def table = once { puts("computing"); Any[1, 2, 3] }
p(table)
# => computing
# => [1, 2, 3]
p(table)                         # => [1, 2, 3]
p(equal?(table, table))          # => true
```

```ruby error
def rec(n) = once { rec(n) }
rec(1)                           # !> SystemStackError: once: the block reached its own once again while computing it
```

## rand

`Kernel.rand([Integer|Float])`

Ruby の `rand` ですが、引数は厳密です。引数が無ければ 0.0 以上 1.0 未満の Float。Integer `n` なら 0 以上 `n` 未満の Integer。Float `x` なら 0.0 以上 `x` 未満の Float。上限は正でなければならず、0・0.0・負の数は `ArgumentError`（`invalid argument - 0`）です（Ruby は `|n|` を使い、0 なら Float を返します）。Range は受け付けません（静的に `type` の問題）。

```ruby
f = rand
p(f >= 0.0 && f < 1.0)           # => true
i = rand(6)
p(i >= 0 && i < 6)               # => true
g = rand(2.5)
p(g >= 0.0 && g < 2.5)           # => true
```

```ruby error
p(rand(0))                       # !> ArgumentError: Kernel.rand: invalid argument - 0
```

## srand

`Kernel.srand([Integer])`

乱数の種を設定し、前の種（Integer）を返します（Ruby の `srand`）。引数が無ければ新しい種を無作為に選びます。同じ種からの `rand` の列は同じです。

```ruby
srand(7)
a = Array.map(Any[1, 2, 3]) { rand(1000) }
srand(7)
b = Array.map(Any[1, 2, 3]) { rand(1000) }
p(a == b)                        # => true
p(srand(1))                      # => 7
```

## sleep

`Kernel.sleep([Integer|Float|Rational])`

指定した秒数だけ止まり、眠った秒数（Integer に丸めたもの、Ruby の `sleep`）を返します。引数が無ければ永久に止まります（他のスレッドに起こされるまで）。

```ruby
p(sleep(0))                      # => 0
p(sleep(1r/100))                 # => 0
```

## exit

`Kernel.exit([Integer|Boolean])`

プログラムを終了状態 `status` で終えます。Integer はそのまま、true は 0、false は 1、省略は 0。`rescue` では捕まえられず（`rescue => e` も通り抜けます）、途中の `ensure` 節と `at_exit` のブロックは走ります。検査器は `exit` の後のコードを到達しないものとして扱います（型 `[]`: 値を返しません）。

```ruby
at_exit { puts("at_exit") }
begin
  exit(true)
rescue => e
  puts("not caught")
ensure
  puts("ensure")                 # => ensure
end
puts("not reached")              # => at_exit
```

```ruby error
puts("start")                    # !> start
exit(3)
puts("not reached")
```

## at_exit

`Kernel.at_exit() { }`

ブロックを登録して nil を返します。登録したブロックはプログラムが終わるとき（普通に、`exit` で、または捕まえられなかった例外で）後に登録したものから順に走ります（Ruby の `at_exit`）。

```ruby
at_exit { puts("bye 1") }
at_exit { puts("bye 2") }
puts("main")
# => main
# => bye 2
# => bye 1
```

## system

`Kernel.system(String, *String)`

コマンドを子プロセスとして走らせ、終わるまで待ちます（Ruby の `system`）。引数が 1 つならシェルを通し、複数なら最初がコマンド、残りがその引数です。戻り値は、終了状態 0 なら true、0 以外なら false、起動できなければ nil（`Boolean | nil`）。子プロセスの出力はそのまま出力に出ます。出力を String として受け取るには `Open3.capture2`・`capture3` を使います。

```ruby
p(system("echo", "hi"))
# => hi
# => true
p(system("false"))               # => false
p(system("/no/such/command"))    # => nil
```

## ARGV

`Kernel.ARGV()`

プログラムのコマンドライン引数の Array（String の Array）。Ruby の定数のように `ARGV` と書きますが操作で、毎回同じ Array を返すので `Array.shift(ARGV)` や `OptionParser` の `parse!` で縮めると以後の `ARGV` にも反映されます。要素の String は凍結されていて、その場で変える操作（`String.concat` など）は `TypeError` です。

```ruby
p(ARGV)                          # => []
Array.push(ARGV, "x")
p(ARGV)                          # => ["x"]
p(equal?(ARGV, ARGV))            # => true
```

## PROGRAM_NAME

`Kernel.PROGRAM_NAME()`

実行中のプログラム（最初のファイル）のパス（Ruby の `$0`）。他の Kernel の操作と違い、裸の `PROGRAM_NAME` は型名として読まれて拒まれるので（`type PROGRAM_NAME cannot be used as a value`）、`Kernel.PROGRAM_NAME` と書きます。

```ruby
p(String.end_with?(Kernel.PROGRAM_NAME, ".sake"))   # => true
```

# Exceptions

組み込みの例外型です。組み込みの操作が実行時に失敗したときに投げるもので、プログラム自身も `raise E, "msg"` で投げられます。各型はフィールド `message` だけを持つクラスとして宣言されていて（[クラス](../07-classes.md)）、他のクラスと同じ操作が使えます:

- `E.new(message)` が例外値を作ります（`message` は普通 String ですが、型は検査されません）。`raise E, "msg"` は `raise E.new("msg")` の略、`raise E` はメッセージを型名にします。`raise "msg"` は `RuntimeError` です。`raise` は構文で、[例外とエラー](../08-exceptions.md)にあります。
- `E.message(e)` がメッセージを読み、`E.set_message(e, s)` が書き換えます（`e.E.message` も同じ）。古い `E.get_message` は拒まれ、`E.message` に直すよう案内されます。どの型の例外値でも読めるのが `Exception.message(e)` で、`rescue => e` のように型が和になっているときに使います。
- `Exception.backtrace(e)` は投げられたときの呼び出しの列（`"FILE:LINE:in 'FUNCTION'"` の Array、内側が先）、`Exception.cause(e)` はそのとき rescue 節で扱っていた例外です。まだ投げていない値ではどちらも nil です（[バックトレースと原因](../08-exceptions.md)）。
- `rescue E => e` は列挙した型を捕まえます。組み込みの型は Ruby の親子関係のとおりで、`rescue IndexError` は `KeyError` も、`rescue IOError` は `EOFError` も、`rescue RangeError` は `FloatDomainError` も、`rescue ArgumentError` は `Math::DomainError` も捕まえます。それを親に書いたクラス（`class E < RangeError`）も捕まえます。ユーザの `class B < A` は書き写しなので `rescue A` は B を捕まえません。まとめるには、型が include したモジュールを書きます（`rescue M`）。複数は `rescue A, B => e`、すべては `rescue => e`（`rescue StandardError`、`rescue Exception` も同じ）です。
- `p(e)` は `#<E: message>`、`==` はフィールドで比べます。
- 組み込みの操作が投げた例外のメッセージは Ruby の文（`divided by 0`）で、rescue されずにプログラムを終えたときの報告には操作名も付きます（`ZeroDivisionError: Kernel.Rational: divided by 0`）。
- 組み込みの操作の中で Ruby が投げた例外が、バックトレース付きの生の Ruby エラーとして漏れることはありません。同じ種類の Sake の例外になり、他と同じく rescue でき、メッセージは Ruby のもの（Ruby の `Sake::Tuple` は `Tuple`）です。Ruby の `EOFError`・`Errno::*`・`ClosedQueueError` は `IOError`、`FrozenError` は `TypeError`、`Math::DomainError` はそのまま `Math::DomainError`、Ruby 自身の `RuntimeError`（不正な文字列の `String.undump`）は `ArgumentError` になります。Sake の `RuntimeError` はプログラム自身の `raise` からだけ生じます。

`Math::DomainError` も組み込みの例外型で、`rescue Math::DomainError => e` と `raise Math::DomainError, "msg"` に書けますが、入れ子の名前なので `Math::DomainError.new(...)` と `Math::DomainError.message(e)` は書けません（`Exception.message(e)` で読みます）。`Math.sqrt(-1)`、`Math.log(-1)`、`Integer.sqrt(-1)`、`Integer.digits(-1)`、負の Float `x` の `x ** 0.5`（`-8.0 ** 0.5 is not a real number (a negative base with a fractional exponent)`。Ruby は Complex を返します）が投げます。`SystemStackError`（深すぎる再帰、`once` の再入）、`LocalJumpError`、`NotImplementedError` はプログラムの誤りで、rescue できず、`rescue` に書くのは静的エラーです。

型の誤り（`TypeError`）やパターンの不一致（`NoMatchingPatternError`）の多くは、実行前の検査が `type` の問題として止めるので、実行時に届くのは検査が見られなかった場所（`Any` を受ける操作、`--strict=0` で走らせたプログラム）だけです。

```ruby
begin
  Integer("x")
rescue ArgumentError, TypeError => e
  puts(Exception.message(e))       # => invalid value for Integer(): "x"
end
e = KeyError.new("missing")
p(e)                               # => #<KeyError: missing>
p(KeyError.message(e))             # => "missing"
KeyError.set_message(e, "other")
p(Exception.message(e))            # => "other"
p(e == KeyError.new("other"))      # => true
```

## RuntimeError

`RuntimeError.new(message)`

`raise "msg"`（型を書かない `raise`）が投げる型です。組み込みの操作が自分から投げることはなく、`Thread.raise(t, msg)` だけが相手のスレッドに投げ、`Thread.value(t)` や `Thread.join(t)` がそれを届けます（操作の中の Ruby の `RuntimeError`、たとえば `String.undump` のものは `ArgumentError` になります）。プログラムの「その他の失敗」に使います。したがって検査器は、本体が `RuntimeError` を投げえない `rescue RuntimeError` に警告を出します（`the begin body never raises RuntimeError [unused-rescue]`。`Thread.value` / `Thread.join` は `Thread.raise` を呼ぶプログラムでだけ数える、というヒント付き）。下の例ではこの節は何も捕まえず、`String.undump` の `ArgumentError` でプログラムが止まります。

```ruby
begin
  raise "plain"
rescue RuntimeError => e
  p(e)                             # => #<RuntimeError: plain>
end
```

```ruby error
begin
  String.undump("\"abc")
rescue RuntimeError => e           # !> warning: rescue RuntimeError: the begin body never raises RuntimeError [unused-rescue]
  p(e)
end
```

## ArgumentError

`ArgumentError.new(message)`

引数の値が受け付けられないとき。投げる操作: `Integer`、`Float`、`Rational` の読めない String、`format` の引数の過不足・数でない値・無いキー、`rand(0)` と負の上限、負のサイズ（`Array.first(a, -1)`）、`Integer ** 負の Integer`、`Regexp.new(s, flags)` の不正なフラグ、`Time.new`・`Time.at`・`Time.now` の範囲外の値や不正なゾーン、`Integer.to_s(n, base)` の不正な基数、`String.unpack` の不正な書式、`String.ljust` の空の詰め文字、`tr` の逆向きの範囲、dump された文字列でないものの `String.undump`（`unterminated dumped string`。Ruby では RuntimeError）、`ENV.set("", v)` と `Process.clock_gettime(999)`（OS が拒む引数）、`Zlib` の壊れたデータ（`incorrect header check`）、ブロックの引数の数の不一致。比べられない要素（`Array.sort`・`max`・`min`・`Tuple.max`・`Set.sort` と、ブロックの結果を通じた `*_by` の形）は、検査器が要素の型を見られるなら静的な `type` の問題で、実行時の `ArgumentError` に届くのは NaN のように見られない場合だけです。

```ruby
begin
  Array.sort(Any[1.0, Float.NAN])
rescue ArgumentError => e
  puts(Exception.message(e))       # => cannot compare elements of types Float
end
begin
  2 ** -1
rescue ArgumentError => e
  puts(Exception.message(e))       # => Integer ** negative Integer (2 ** -1) is an error; for a Rational, write 2r ** -1
end
begin
  String.undump("\"abc")
rescue ArgumentError => e
  puts(Exception.message(e))       # => unterminated dumped string
end
```

```ruby error
Array.sort(Any[1, "a"])          # !> Array.sort: elements compared in order may be (Integer, String), which cannot be compared [type]
```

## TypeError

`TypeError.new(message)`

値の型が合わないとき: 操作が受け取った引数が違う型、左のオペランドの型が支えない演算子、型付き Array（`Integer[]` など）への違う型の書き込み、Tuple でも Array でもない値からの多重代入、凍結された String（Hash のキー、Set の要素、Symbol の名前、`ARGV` の要素）のその場での変更（`cannot change this String in place: it is a Hash key, a Set element, a Symbol's name, or a program argument`）、`Exception.message` に例外でない値。検査器が要素の型を見られなかった場所で操作の中の Ruby が `TypeError` や `NoMethodError` を出したときもこの型です: `Array.pack(Any["a"], "C")`（`no implicit conversion of String into Integer`）、`Range.first(1.0..2.0, 2)`（`can't iterate from Float`）、`--strict=0` で String でないキーや値を渡した `ENV.replace`（`keys and values must be String, got String => Integer`）。これらの大半は実行前の検査が静的に止めるので、実行時に届くのは検査が通した場所だけです。

```ruby
begin
  Array.pack(Any["a"], "C")
rescue TypeError => e
  puts(Exception.message(e))       # => no implicit conversion of String into Integer
end
```

```ruby error
Array.push(Integer[], "a")         # !> Array.push: an element must be Integer, but is String
```

## KeyError

`KeyError.new(message)`

無いキー: `Hash.fetch`（既定値もブロックも無いとき）、`Hash.fetch_values`、`ENV.fetch`、無いフィールドを名乗る Record パターン。`format` の `%<name>` の無いキーは `ArgumentError` です。

```ruby
h = Hash.of("a" => 1)
begin
  Hash.fetch(h, "b")
rescue KeyError => e
  puts(Exception.message(e))       # => key not found: "b"
end
p(Hash.fetch(h, "b", 0))           # => 0
```

## IndexError

`IndexError.new(message)`

範囲外の添字: `Array.fetch`、Tuple の外の添字（実行時に届いたもの。リテラルの添字は静的に止まります）、T の Array の末尾の先への書き込み（`Integer[1, 2][5] = 1`。隙間が nil になるため）、`Array.insert` の末尾より先の位置（`index 3 is past the end of the Array (length 1); the gap would be nil`。Ruby は隙間を nil で埋めます）、Regexp に無いグループの `MatchData.begin(m, 5)`（`index 5 out of matches`）、長さの違う行の `Array.transpose`、文字の途中を指す `String.byteindex` のオフセット。`x[k]` は範囲外で nil を返し、例外にはなりません。

```ruby
def at(t, i) = t[i]
begin
  at([1, 2], 5)
rescue IndexError => e
  puts(Exception.message(e))       # => index 5 is outside a Tuple of length 2
end
begin
  Array.fetch(Any[3, 1], 9)
rescue IndexError => e
  puts(Exception.message(e))       # => index 9 outside of array bounds: -2...2
end
```

## ZeroDivisionError

`ZeroDivisionError.new(message)`

Integer（と Rational）のゼロ除算: `/`、`%`、`Integer.divmod`、`div`、`modulo`、`remainder`、`ceildiv`、`Rational(a, 0)`、`Rational.quo`。Float の `1.0 / 0` は Ruby と同じく Infinity で、例外にはなりません。

```ruby
begin
  7 % 0
rescue ZeroDivisionError => e
  puts(Exception.message(e))       # => divided by 0
end
p(1.0 / 0)                         # => Infinity
```

## RangeError

`RangeError.new(message)`

値が表せる範囲の外: 有限の Range が要る操作に終端の無い Range（`Range.to_a(1..)`、`Range.last(1..)`、`Range.sort` など）、`Range.first` に始端の無い Range（`cannot get the first element of beginless range`）、`Integer.chr` の文字にならない Integer（`256 out of char range`）、`Integer.pow(2, -1, 7)` の負の指数、`Range.sum` の Complex の初期値。

```ruby
begin
  Range.to_a(1..)
rescue RangeError => e
  puts(Exception.message(e))       # => cannot do this on an endless Range 1..
end
begin
  Integer.chr(256)
rescue RangeError => e
  puts(Exception.message(e))       # => 256 out of char range
end
```

## FloatDomainError

`FloatDomainError.new(message)`

NaN や Infinity を Integer や Rational にしようとしたとき: `Float.to_i`、`Arithmetic.to_i`、`Arithmetic.round`・`floor`・`ceil`・`truncate`、`Float.to_r`、`Float.rationalize`、`Float.numerator`・`denominator`、`Kernel.Integer(x)`、`Kernel.Rational(x)`。メッセージは値の名前です。どれも rescue できます。

```ruby
begin
  Float.to_i(Float.INFINITY)
rescue FloatDomainError => e
  puts(Exception.message(e))       # => Infinity
end
begin
  Float.to_r(Float.NAN)
rescue FloatDomainError => e
  puts(Exception.message(e))       # => NaN
end
begin
  Integer(Float.NAN)
rescue FloatDomainError => e
  puts(Exception.message(e))       # => NaN
end
```

## IOError

`IOError.new(message)`

入出力の失敗: `File.read`、`File.write`、`File.open`、`Dir.mkdir`、`Dir.children` など File と Dir の操作（Ruby の `Errno::ENOENT` などがこの 1 つの型になり、メッセージは Ruby のもの）、閉じた IO への操作、ファイルでないストリームの `IO.size`（`not a file`）、端末でない IO への端末の操作（`IO.winsize` など。`not a terminal`）、ソケットのエラー（接続拒否、リセット、解決できない名前、タイムアウト）、閉じた Queue への `Queue.push`。操作の中の Ruby の `EOFError` も Sake の `EOFError` ではなくこの型になります。

```ruby
begin
  File.read("no-such-file")
rescue IOError => e
  puts(Exception.message(e))       # => No such file or directory @ rb_sysopen - no-such-file
end
begin
  IO.size(IO.stdin)
rescue IOError => e
  puts(Exception.message(e))       # => not a file
end
q = Queue.new
Queue.close(q)
begin
  Queue.push(q, 1)
rescue IOError => e
  puts(Exception.message(e))       # => push to a closed Queue
end
```

## EOFError

`EOFError.new(message)`

入力の終わりに達した読み出し。Ruby では `IO#readline` などが投げますが、Sake の読み出し操作（`IO.read(io, n)`、`IO.gets`、`IO.getc`、`gets`）は終わりで nil を返すので、これを投げる組み込みの操作はありません（操作の中の Ruby の `EOFError` は `IOError` になります）。プログラム自身の「もう入力が無い」に使えます。`IOError` とは別の型で、`rescue IOError` では捕まりません。

```ruby
def next_token(xs) = Array.shift(xs) || raise(EOFError, "no more tokens")
begin
  next_token(Any[])
rescue EOFError => e
  puts(Exception.message(e))       # => no more tokens
end
```

## EncodingError

`EncodingError.new(message)`

文字列のエンコーディングの誤り: `String.encode` で変換できないバイト、エンコーディングの合わない String の連結や比較など、操作の中で Ruby が `EncodingError`（`Encoding::UndefinedConversionError` など）を出したもの。

```ruby
begin
  String.encode("\xff", "UTF-16")
rescue EncodingError => e
  puts(Exception.message(e))       # => "\xFF" on UTF-8
end
```

## RegexpError

`RegexpError.new(message)`

不正な正規表現: 式を埋め込んだリテラル `/#{s}/` のパターンが不正なとき、`Regexp.new(s)` の不正なパターン、String の操作に渡した不正なパターン String（`String.match?("a+c", "+")`）。リテラルに直接書いたパターンは構文エラーとして実行前に止まります。

```ruby
s = "("
begin
  r = /#{s}/
rescue RegexpError => e
  puts(Exception.message(e))       # => end pattern with unmatched parenthesis: /(/
end
begin
  Regexp.new("(")
rescue RegexpError => e
  puts(Exception.message(e))       # => end pattern with unmatched parenthesis: /(/
end
begin
  String.match?("a+c", "+")
rescue RegexpError => e
  puts(Exception.message(e))       # => target of repeat operator is not specified: /+/
end
```

## NoMatchingPatternError

`NoMatchingPatternError.new(message)`

`case`/`in` のどの枝にも値が合わず `else` も無いとき、`x => pattern` が合わないとき。検査器は値の型から合う枝が無いことを静的に見つけて `type` の問題として止めるので（下の例）、実行時に投げられるのは検査が通した場所、たとえば `--strict=0` で走らせたプログラムです。メッセージは合わなかった値を述べます。

```ruby error
def kind(x)
  case x
  in Integer then "int"
  end
end
kind("s")                          # !> case/in: no `in` branch matches String
```

## ThreadError

`ThreadError.new(message)`

スレッドの操作の誤り: 持っている Mutex をもう一度 `Mutex.lock` や `Mutex.synchronize`、持っていない Mutex の `Mutex.unlock`、今のスレッド自身の `Thread.join`。すべてのスレッドが待ちになるデッドロックも Sake の `ThreadError` としてプログラムを終えます（[例外とエラー](../08-exceptions.md)）。

```ruby
m = Mutex.new
Mutex.lock(m)
begin
  Mutex.lock(m)
rescue ThreadError => e
  puts(Exception.message(e))       # => deadlock; recursive locking
end
begin
  Mutex.unlock(Mutex.new)
rescue ThreadError => e
  puts(Exception.message(e))       # => Attempt to unlock a mutex which is not locked
end
begin
  Thread.join(Thread.current)
rescue ThreadError => e
  puts(Exception.message(e))       # => Target thread must not be current thread
end
```

# Integer

Integer は Ruby と同じく大きさに上限の無い整数です: `42`、`-7`、`1_000_000`、`0x1f`、`0b101`、`0o17`、`2 ** 100`（[値と型](../03-values.md)）。変換 `Integer("42")`、`Integer(3.9)` はこの名前空間ではなく Kernel の操作です（`Kernel.Integer`。不正な入力は `ArgumentError`）。Integer は値であり、主語を変更する操作はここにはありません。すべての結果は新しい値です。

Integer に使える演算子は Integer が include するモジュールから来ます（[演算子と添字](../05-operators.md)）: `Arithmetic` が `+ - * / % **` と単項の `-x`、`Comparable` が `<=> < <= > >=`、`Bitwise` が `& | ^ << >>` と単項の `~x` を与え、`==` と `!=` は Kernel のものです。`a + b` は `a` の型で振り分けられるので、左が Integer なら `Integer.+(a, b)` が走ります。以下の `Integer.+(x, y)` などはその関数形です。右側の型は**閉じた表**で決まります: Integer と Integer は Integer、Float とは Float、Rational とは Rational（`**` だけは Rational の指数で `Rational | Float`）、Complex とは Complex。`<` などは Integer、Float、Rational と比べられ、ビット演算子は Integer だけを取ります。それ以外の型の右側（String、nil、Symbol）は静的に `type` の問題（`the operands are (Integer, String), which the left operand's type does not support`）、実行時は `TypeError` です。関数形は第 1 引数も Integer でなければなりません（`Integer.+(1.0, 2)` は `type` の問題。`Float.+` か演算子を使います）。

Ruby と違う点は 2 つ: `Integer ** 負の Integer` は Rational を返さず `ArgumentError` を投げます（`a ** b` の型が `b` の値に依存しないように）。また値に対するメソッド呼び出しはありません（`1.+(2)` は拒否され、`Integer.+(1, 2)` か `1 + 2` と書きます）。`/` と `%` は Ruby と同じく床へ丸め（`-7 / 2` は -4）、0 で割ると `ZeroDivisionError` です。

丸めの一族 `round`、`floor`、`ceil`、`truncate` と `abs`、`to_f`、`to_i`、`zero?` はモジュール `Arithmetic`（[Arithmetic](Arithmetic.md)）にもあり、そちらはどの実数も取ります（Integer、Float、Rational の `x` に `Arithmetic.round(x)`。Ruby の `x.round`）。以下の項目は Integer 専用の形で、Float の主語は `Arithmetic` を使うようヒント付きで拒否されます。結果が nil になりうる操作はこの名前空間にはありません: どの結果も確定した Integer、Float、Rational、String、Boolean、Tuple、Array です。

## Integer[]

`Integer[*Any]`

**Integer の Array** を作ります: 要素がすべて Integer でなければならない型付き Array で、構築時と書き込み（`Array.push`、`a[i] = v` など）のたびに検査されます。別の型のリテラル要素は実行前に拒否され（`element 2 must be Integer, got String`）、別の型の書き込みは静的に `type` の問題、実行時は `TypeError` です。空の Integer の Array は `Integer[]` です。`Any[1, 2]` は要素の型が推論され、書き込まれたものに応じて広がる点が違います。

```ruby
a = Integer[1, 2, 3]
Array.push(a, 4)
p(a)                         # => [1, 2, 3, 4]
p(Array.size(Integer[]))     # => 0
```

```ruby error
Array.push(Integer[], 1.5)   # !> Array.push: an element must be Integer, but is Float
```

## +, -, *

`Integer.+(x, Any)`

`Integer.-(x, Any)`

`Integer.*(x, Any)`

加算・減算・乗算。どんな大きさでも正確です。結果の型は右側に従います: Integer なら Integer、Float なら Float、Rational なら Rational、Complex なら Complex。それ以外の右側は `type` の問題です。単項マイナス `-x` は `Integer.-@` で、演算子としてだけ書けます。

```ruby
p(Integer.+(1, 2))           # => 3
p(Integer.-(1, 2))           # => -1
p(3 * 4)                     # => 12
p(2 + 1.5)                   # => 3.5
p(1 + 1r)                    # => (2/1)
p(2 ** 64 + 1)               # => 18446744073709551617
```

```ruby error
p(1 + "a")                   # !> the operands are (Integer, String), which the left operand's type does not support
```

## /, %

`Integer./(x, Any)`

`Integer.%(x, Any)`

除算と剰余。Integer 同士では Ruby と同じくどちらも**床**へ丸めます: 商は負の無限大の方向へ丸め、余りは除数の符号を取ります（`-7 / 2` は -4、`-7 % 3` は 2、`7 % -3` は -2）。Integer の除数 0 は `ZeroDivisionError`。右側が Float なら結果は Float で、`0.0` で割ると `Infinity`（IEEE）、Rational なら Rational です。`div`、`modulo`、`remainder`、`divmod`、`fdiv`、`ceildiv` も参照。

```ruby
p(7 / 2)                     # => 3
p(-7 / 2)                    # => -4
p(7 % 3)                     # => 1
p(-7 % 3)                    # => 2
p(Integer./(7, 2.0))         # => 3.5
p(1 / 0.0)                   # => Infinity
```

```ruby error
p(Integer./(1, 0))           # !> ZeroDivisionError: Integer./: divided by 0
```

## **

`Integer.**(x, Any)`

べき乗。Integer に非負の Integer の指数なら正確な Integer。Float の指数は Float を与えます。**Rational の指数**は、整数値なら Rational（`2 ** 2r` は `(4/1)`）、そうでなければ Float（`2 ** (1r/2)` は `1.4142135623730951`）になるので、検査器はその結果を `Rational | Float` とします。どちらかとして使う前に `case`/`in` で絞ってください。Ruby と違い、**負の Integer の指数は `ArgumentError`** です（Ruby は Rational を返す）。メッセージが Rational を得る書き方（`2r ** -1`）を教えます。負の底に分数の指数（`(-8) ** 0.5`）は `Math::DomainError` です（Ruby は Complex を返す）。`**` は単項マイナスより強く結合するので Ruby と同じく `-2 ** 2` は -4、右結合です（`2 ** 3 ** 2` は 512）。`pow` も参照。

```ruby
p(2 ** 10)                   # => 1024
p(Integer.**(2, 0))          # => 1
p(2 ** 0.5)                  # => 1.4142135623730951
p(2 ** 2r)                   # => (4/1)
p(2 ** (1r/2))               # => 1.4142135623730951
p(-2 ** 2)                   # => -4
x = 2 ** 2r
case x
in Rational then p(Rational.numerator(x))   # => 4
in Float then p(x)
end
```

```ruby error
p(2 ** -1)                   # !> ArgumentError: Arithmetic.**: Integer ** negative Integer (2 ** -1) is an error; for a Rational, write 2r ** -1
```

```ruby error
p((-8) ** 0.5)               # !> Math::DomainError: Arithmetic.**: -8 ** 0.5 is not a real number (a negative base with a fractional exponent)
```

```ruby error
p(Rational.numerator(2 ** 2r))   # !> Rational.numerator: argument 1 must be Rational, but can be Float
```

## ==, !=

`Integer.==(x, Any)`

`Integer.!=(x, Any)`

等価（`!=` はその否定）。数は型をまたいで比べられます: `1 == 1.0`、`1 == 1r`、`1 == Complex(1, 0)` は true。Ruby と同じく、別の型の値とは決して等しくありません（`1 == "1"` は false、`1 == nil` は false）。関数形 `Integer.==(x, y)` も、右側が他のどんな型でも同じく false（`!=` は true）を返し、エラーにはなりません。

```ruby
p(1 == 1)                    # => true
p(1 == 1.0)                  # => true
p(1 != 1)                    # => false
p(1 == "1")                  # => false
p(1 == nil)                  # => false
p(Integer.==(1, nil))        # => false
p(Integer.==(1, "a"))        # => false
p(Integer.!=(1, "a"))        # => true
```

## <, <=, >, >=

`Integer.<(x, Any)`

`Integer.<=(x, Any)`

`Integer.>(x, Any)`

`Integer.>=(x, Any)`

順序。右側は Integer、Float、Rational です。Complex に順序は無く、String や nil は `type` の問題（`Comparable.<: the operands are (Integer, String) ...`）。結果は true か false。

```ruby
p(1 < 2)                     # => true
p(1 <= 1)                    # => true
p(2 >= 3)                    # => false
p(1 < 1.5)                   # => true
p(Integer.<(1, 2r))          # => true
```

```ruby error
p(1 < "a")                   # !> Comparable.<: the operands are (Integer, String), which the left operand's type does not support
```

## <=>

`Integer.<=>(x, Any)`

左が右（Integer、Float、Rational）より小さければ -1、等しければ 0、大きければ 1。数同士では nil にならないので、検査器は結果を Integer とします。それ以外の右側は `type` の問題です。

```ruby
p(1 <=> 2)                   # => -1
p(2 <=> 1)                   # => 1
p(1 <=> 1)                   # => 0
p(Integer.<=>(1, 1.5))       # => -1
```

## &, |, ^

`Integer.&(x, Any)`

`Integer.|(x, Any)`

`Integer.^(x, Any)`

2 の補数のビットに対するビット積・ビット和・排他的論理和（Ruby と同じ）。負の数は上位に無限に 1 が並んでいるものとして振る舞います。両側とも Integer でなければならず、右側の Float は `type` の問題（`Bitwise.&: the operands are (Integer, Float) ...`）。単項の補数 `~x` は `Integer.~` で、演算子としてだけ書けます。

```ruby
p(6 & 3)                     # => 2
p(6 | 3)                     # => 7
p(6 ^ 3)                     # => 5
p(~5)                        # => -6
p(Integer.&(6, 3))           # => 2
```

```ruby error
p(6 & 1.5)                   # !> Bitwise.&: the operands are (Integer, Float), which the left operand's type does not support
```

## <<, >>

`Integer.<<(x, Any)`

`Integer.>>(x, Any)`

Integer のビット数だけ左・右へシフトします（Ruby と同じ）: `x << n` は `x * 2**n`（正確で、必要なだけ伸びる）、`x >> n` は床へ丸めます（`-1 >> 1` は -1）。負のビット数は逆方向へシフトします（`1 << -1` は 0）。右側は Integer でなければなりません。

```ruby
p(1 << 4)                    # => 16
p(256 >> 4)                  # => 16
p(-1 >> 1)                   # => -1
p(1 << 100 == 2 ** 100)      # => true
```

## bit_length

`Integer.bit_length(x)`

2 の補数で数を表すのに要るビット数（符号ビットを除く。Ruby と同じ）: 255 は 8、256 は 9、0 と -1 は 0、-256 は 8。

```ruby
p(Integer.bit_length(255))   # => 8
p(Integer.bit_length(256))   # => 9
p(Integer.bit_length(0))     # => 0
p(Integer.bit_length(-1))    # => 0
```

## allbits?, anybits?, nobits?

`Integer.allbits?(x, Integer)`

`Integer.anybits?(x, Integer)`

`Integer.nobits?(x, Integer)`

マスクで立っているビットが数の中ですべて立っているか、どれかが立っているか、どれも立っていないか: `x & mask == mask`、`x & mask != 0`、`x & mask == 0`。

```ruby
p(Integer.allbits?(6, 2))    # => true
p(Integer.allbits?(6, 3))    # => false
p(Integer.anybits?(6, 3))    # => true
p(Integer.nobits?(6, 1))     # => true
```

## div, modulo, remainder

`Integer.div(x, Integer|Float|Rational)`

`Integer.modulo(x, Integer)`

`Integer.remainder(x, Integer)`

`div` は床へ丸めた商で、除数が Float や Rational でも **Integer** です（`Integer.div(7, 2.0)` は 3。`7 / 2.0` は 3.5）。`modulo` は `%` と同じで、除数の符号を取る余り。`remainder` は Ruby と同じく**被除数**の符号を取る余りです（`Integer.remainder(-7, 3)` は -1。`-7 % 3` は 2）。除数 0（`0.0` も）は `ZeroDivisionError`。

```ruby
p(Integer.div(-7, 2))        # => -4
p(Integer.div(7, 2.0))       # => 3
p(Integer.modulo(-7, 3))     # => 2
p(Integer.remainder(-7, 3))  # => -1
p(Integer.remainder(7, -3))  # => 1
```

```ruby error
p(Integer.modulo(7, 0))      # !> ZeroDivisionError: Integer.modulo: divided by 0
```

## divmod

`Integer.divmod(x, Integer)`

床へ丸めた除算の Tuple `[商, 余り]`。`q * b + r == a` が成り立ち、`r` は除数の符号を取ります。除数 0 は `ZeroDivisionError`。Ruby と違い除数は Integer でなければなりません（`Float.divmod` は Float の主語を取ります）。

```ruby
p(Integer.divmod(7, 2))      # => [3, 1]
p(Integer.divmod(-7, 2))     # => [-4, 1]
q, r = Integer.divmod(17, 5)
p([q, r])                    # => [3, 2]
```

```ruby error
p(Integer.divmod(7, 0))      # !> ZeroDivisionError: Integer.divmod: divided by 0
```

## ceildiv

`Integer.ceildiv(x, Integer)`

正の無限大の方向へ丸めた商（Ruby の `ceildiv`）: `Integer.ceildiv(7, 2)` は 4、`Integer.ceildiv(-7, 2)` は -3。除数 0 は `ZeroDivisionError`。

```ruby
p(Integer.ceildiv(7, 2))     # => 4
p(Integer.ceildiv(-7, 2))    # => -3
p(Integer.ceildiv(6, 2))     # => 3
```

## fdiv

`Integer.fdiv(x, Integer)`

Float としての商、`Integer.to_f(a) / b`。除数 0 は例外にならず、Ruby と同じく `Infinity`、`-Infinity`、`NaN`（`0 / 0`）になります。Ruby と違い除数は Integer でなければなりません。

```ruby
p(Integer.fdiv(7, 2))        # => 3.5
p(Integer.fdiv(1, 3))        # => 0.3333333333333333
p(Integer.fdiv(1, 0))        # => Infinity
```

## pow

`Integer.pow(x, Integer, [Integer])`

`Integer.pow(a, b)` は Integer の指数の `a ** b` で、負の指数は同じ `ArgumentError`。`Integer.pow(a, b, m)` は `a ** b` を `m` で割った余りで、Ruby と同じく巨大なべきを作らずに計算します。結果は `m` の符号を取ります。法付きのとき、負の指数は `RangeError`（メッセージは Ruby のもので、指数を 1 番目の引数と数えます）、法 0 は `ZeroDivisionError` で、どちらも `rescue` できます。

```ruby
p(Integer.pow(2, 10))        # => 1024
p(Integer.pow(2, 10, 1000))  # => 24
p(Integer.pow(3, 100, 7))    # => 4
p(Integer.pow(2, 10, -7))    # => -5
begin
  Integer.pow(2, 3, 0)
rescue ZeroDivisionError => e
  p(Exception.message(e))    # => "divided by 0"
end
```

```ruby error
p(Integer.pow(2, -1))        # !> ArgumentError: Integer.pow: Integer ** negative Integer (2 ** -1) is an error; for a Rational, write 2r ** -1
```

```ruby error
p(Integer.pow(2, -1, 7))     # !> RangeError: Integer.pow: Integer#pow() 1st argument cannot be negative when 2nd argument specified
```

## gcd, lcm

`Integer.gcd(x, Integer)`

`Integer.lcm(x, Integer)`

最大公約数と最小公倍数。Ruby と同じく常に非負です。`gcd(0, n)` は `|n|`、`gcd(0, 0)` は 0、`lcm(0, n)` は 0。

```ruby
p(Integer.gcd(12, 18))       # => 6
p(Integer.gcd(-12, 18))      # => 6
p(Integer.gcd(0, 0))         # => 0
p(Integer.lcm(4, 6))         # => 12
p(Integer.lcm(0, 6))         # => 0
```

## gcdlcm

`Integer.gcdlcm(x, Integer)`

Tuple `[gcd, lcm]`。

```ruby
g, l = Integer.gcdlcm(4, 6)
p([g, l])                    # => [2, 12]
```

## sqrt

`Integer.sqrt(x)`

整数平方根: 2 乗が数を超えない最大の Integer（Ruby の `Integer.sqrt`）。どんな大きさでも正確で、`Math.sqrt` は Float を返すところです。負の数は `Math::DomainError`（メッセージは Ruby のもの）を投げ、`rescue` できます。

```ruby
p(Integer.sqrt(16))          # => 4
p(Integer.sqrt(17))          # => 4
p(Integer.sqrt(10 ** 20))    # => 10000000000
```

```ruby error
p(Integer.sqrt(-1))          # !> Math::DomainError: Integer.sqrt: Numerical argument is out of domain - "isqrt"
```

## abs, magnitude

`Integer.abs(x)`

`Integer.magnitude(x)`

絶対値（Integer）。`Arithmetic.abs(x)` はどの実数にも同じことをします。

```ruby
p(Integer.abs(-5))           # => 5
p(Integer.magnitude(5))      # => 5
```

## even?, odd?

`Integer.even?(x)`

`Integer.odd?(x)`

偶数か奇数か。0 は偶数、-3 は奇数です。

```ruby
p(Integer.even?(4))          # => true
p(Integer.even?(-3))         # => false
p(Integer.odd?(-3))          # => true
```

## zero?, positive?, negative?

`Integer.zero?(x)`

`Integer.positive?(x)`

`Integer.negative?(x)`

数が 0 か、0 より大きいか、0 より小さいか。0 は正でも負でもありません。`Arithmetic.zero?(x)` はどの実数も取ります。

```ruby
p(Integer.zero?(0))          # => true
p(Integer.positive?(0))      # => false
p(Integer.negative?(-1))     # => true
```

## succ, next

`Integer.succ(x)`

`Integer.next(x)`

数に 1 を足したもの。

```ruby
p(Integer.succ(5))           # => 6
p(Integer.next(-1))          # => 0
```

## pred

`Integer.pred(x)`

数から 1 を引いたもの。

```ruby
p(Integer.pred(5))           # => 4
p(Integer.pred(0))           # => -1
```

## times

`Integer.times(x) { }`

0, 1, ..., n-1 をブロックへ渡し、n（主語）を返します（Ruby と同じ）。n が 0 以下ならブロックは呼ばれません。ブロックは**必須**です（ブロック無しの Ruby の `times` は Enumerator を返す）。ブロックの引数は 1 つ。`break v` はループを終えて `v` を結果にし、`next` は次の回へ進み、関数の中の `return` は関数から戻ります。

```ruby
n = Integer.times(3) { |i| puts(i) }   # => 0
                                       # => 1
                                       # => 2
p(n)                                   # => 3
sum = 0
Integer.times(4) { |i| sum += i }
p(sum)                                 # => 6
p(Integer.times(0) { |i| puts(i) })    # => 0
p(Integer.times(3) { |i| break i * 10 if i == 1 })   # => 10
```

```ruby error
Integer.times(3)                       # !> Integer.times requires a block
```

## upto

`Integer.upto(x, Integer) { }`

a, a+1, ..., b をブロックへ渡し、a（主語）を返します（Ruby の `a.upto(b)`）。a が b より大きければブロックは呼ばれません。ブロックは必須です。

```ruby
p(Integer.upto(1, 3) { |i| puts(i) })  # => 1
                                       # => 2
                                       # => 3
                                       # => 1
p(Integer.upto(3, 1) { |i| puts(i) })  # => 3
```

## downto

`Integer.downto(x, Integer) { }`

a, a-1, ..., b をブロックへ渡し、a を返します（Ruby の `a.downto(b)`）。a が b より小さければブロックは呼ばれません。ブロックは必須です。

```ruby
p(Integer.downto(3, 1) { |i| puts(i) })  # => 3
                                         # => 2
                                         # => 1
                                         # => 3
```

## step

`Integer.step(x, Integer, Integer) { }`

`Integer.step(a, limit, step)` は a, a+step, a+2·step, ... を、値が（step の向きで）limit を越えない間ブロックへ渡し、a を返します（Ruby の `a.step(limit, step)`）。limit と step はどちらも必須の Integer です（Ruby の Float の刻みやキーワード形はありません）。刻み 0 は `ArgumentError`。負の刻みは下ります。

```ruby
p(Integer.step(1, 10, 3) { |i| puts(i) })   # => 1
                                            # => 4
                                            # => 7
                                            # => 10
                                            # => 1
p(Integer.step(10, 1, -3) { |i| print(i, " ") })   # => 10 7 4 1 10
```

```ruby error
Integer.step(1, 10, 0) { |i| puts(i) }      # !> ArgumentError: Integer.step: step can't be 0
```

## clamp

`Integer.clamp(x, Integer, Integer)`

数を区間に収めたもの: `lo` より下なら `lo`、`hi` より上なら `hi`、それ以外はそのまま。Ruby と違い Range の形（`clamp(1..10)`）はありません。`lo` が `hi` より大きいと `ArgumentError`（`min argument must be less than or equal to max argument`）です。

```ruby
p(Integer.clamp(5, 1, 10))   # => 5
p(Integer.clamp(-5, 1, 10))  # => 1
p(Integer.clamp(50, 1, 10))  # => 10
```

```ruby error
p(Integer.clamp(5, 10, 1))   # !> ArgumentError: Integer.clamp: min argument must be less than or equal to max argument
```

## between?

`Integer.between?(x, Integer, Integer)`

`lo <= x <= hi` なら true。両端を含みます。`lo` が `hi` より大きければ false です。

```ruby
p(Integer.between?(5, 1, 10))   # => true
p(Integer.between?(1, 1, 10))   # => true
p(Integer.between?(0, 1, 10))   # => false
```

## round

`Integer.round(x, [Integer])`

桁数無しなら数そのもの。負の桁数 -d なら 10^d の倍数へ丸め、半分はゼロから遠い側へ寄せます（Ruby と同じ。`Integer.round(1250, -2)` は 1300、`Integer.round(-1250, -2)` は -1300）。正の桁数は数を変えません。結果は常に Integer。主語は Integer だけで、Float は `type` の問題になり、どの実数も丸める `Arithmetic.round(x)` をヒントが示します。

```ruby
p(Integer.round(1234))       # => 1234
p(Integer.round(1234, -2))   # => 1200
p(Integer.round(1250, -2))   # => 1300
p(Integer.round(-1250, -2))  # => -1300
p(Integer.round(1234, 2))    # => 1234
```

```ruby error
p(Integer.round(2.5))        # !> Integer.round: argument 1 must be Integer, but is Float
```

## floor, ceil

`Integer.floor(x, [Integer])`

`Integer.ceil(x, [Integer])`

桁数無しなら数そのもの。負の桁数 -d なら 10^d の倍数へ、`floor` は下（負の無限大の方向）へ、`ceil` は上（正の無限大の方向）へ丸めます（Ruby と同じ）。常に Integer。Float には `Arithmetic.floor` か `Float.floor` を使います。

```ruby
p(Integer.floor(1234, -2))   # => 1200
p(Integer.floor(-1234, -2))  # => -1300
p(Integer.ceil(1234, -2))    # => 1300
p(Integer.ceil(-1234, -2))   # => -1200
p(Integer.floor(5))          # => 5
```

## truncate

`Integer.truncate(x, [Integer])`

桁数無しなら数そのもの。負の桁数 -d なら 10^d の倍数へゼロの方向へ丸めます。常に Integer。

```ruby
p(Integer.truncate(1234, -2))    # => 1200
p(Integer.truncate(-1234, -2))   # => -1200
```

## digits

`Integer.digits(x)`

10 進の各桁を下の桁から並べた新しい Array（基数無しの Ruby の `digits`。`Integer.digits(1234)` は `[4, 3, 2, 1]`、0 は `[0]`）。型付きの `Integer[]` で、別の型の値を push すると `type` の問題です。負の数は `Math::DomainError`（`out of domain`）を投げます。Ruby と違い基数の引数は無く、`to_s(n, base)` と `String.chars` を使います。

```ruby
p(Integer.digits(1234))      # => [4, 3, 2, 1]
p(Integer.digits(0))         # => [0]
p(Array.sum(Integer.digits(999)))   # => 27
d = Integer.digits(12)
Array.push(d, 9)
p(d)                         # => [2, 1, 9]
```

```ruby error
Array.push(Integer.digits(12), "x")   # !> Array.push: an element must be Integer, but is String
```

```ruby error
p(Integer.digits(-1))        # !> Math::DomainError: Integer.digits: out of domain
```

## to_s

`Integer.to_s(x, [Integer])`

数を指定の基数（2 から 36。省略時 10）で書いた String。9 を超える桁は小文字で、負の数には先頭に `-` が付きます。2..36 の外の基数は `ArgumentError`（`invalid radix 1`）。`String.to_i(s, base)` が読み戻します。

```ruby
p(Integer.to_s(255))         # => "255"
p(Integer.to_s(255, 2))      # => "11111111"
p(Integer.to_s(-255, 16))    # => "-ff"
p(Integer.to_s(35, 36))      # => "z"
```

```ruby error
p(Integer.to_s(255, 37))     # !> ArgumentError: Integer.to_s: invalid radix 37
```

## to_f

`Integer.to_f(x)`

数を Float にしたもの（正確に表せない大きな数は最も近いもの）。`Arithmetic.to_f(x)` はどの実数も取ります。

```ruby
p(Integer.to_f(3))           # => 3.0
```

## to_i, to_int

`Integer.to_i(x)`

`Integer.to_int(x)`

数そのもの。どの実数向けにも書かれたコードのためにあり、`Arithmetic.to_i(x)` は Float や Rational を Integer へ切り捨てます。String の変換 `Integer(s)` は Kernel のもので、この操作ではありません。

```ruby
p(Integer.to_i(3))           # => 3
p(Integer.to_int(-3))        # => -3
```

## to_r

`Integer.to_r(x)`

数を分母 1 の Rational にしたもの。

```ruby
p(Integer.to_r(3))           # => (3/1)
```

## rationalize

`Integer.rationalize(x, [Integer|Float|Rational])`

数を Rational にしたもの（`to_r` と同じ）。省略可能な許容誤差は `Float.rationalize` との対称のために受け取るだけで、Integer では結果を変えません。

```ruby
p(Integer.rationalize(3))        # => (3/1)
p(Integer.rationalize(3, 0.5))   # => (3/1)
```

## numerator, denominator

`Integer.numerator(x)`

`Integer.denominator(x)`

分数と見たとき、数は自分自身を分子、1 を分母に持ちます。

```ruby
p(Integer.numerator(6))      # => 6
p(Integer.denominator(6))    # => 1
```

## integer?

`Integer.integer?(x)`

Integer では常に true（Ruby の `Numeric#integer?`）。別の型かもしれない値の型を調べるには `x in Integer` を使います。

```ruby
p(Integer.integer?(6))       # => true
```

## size

`Integer.size(x)`

機械表現のバイト数（Ruby と同じ）: 機械語 1 語に収まる数は 8、それより大きい数はもっと多く。有効なビット数には `bit_length` を使います。

```ruby
p(Integer.size(1))           # => 8
p(Integer.size(2 ** 100))    # => 13
```

## chr

`Integer.chr(x)`

そのバイト値を持つ 1 文字の String。数は 0 から 255 でなければならず、外れると `RangeError`（`256 out of char range`）を投げます（`rescue` できます）。エンコーディング無しの Ruby の `chr` と同じく、0 から 127 は ASCII の String、128 から 255 は 1 バイトのバイナリ String で、UTF-8 の文字列とつなぐと `EncodingError` を投げます。`String.ord` が逆の操作です。255 を超えるコードポイントの String は別の方法で作ります（`format("%c", n)`）。

```ruby
p(Integer.chr(65))           # => "A"
puts(Integer.chr(97))        # => a
p(Integer.chr(10))           # => "\n"
p(String.ord(Integer.chr(200)))   # => 200
begin
  Integer.chr(200) + "é"
rescue EncodingError => e
  p(Exception.message(e))    # => "incompatible character encodings: BINARY (ASCII-8BIT) and UTF-8"
end
```

```ruby error
p(Integer.chr(256))          # !> RangeError: Integer.chr: 256 out of char range
```

## ord

`Integer.ord(x)`

数そのもの（Ruby の `Integer#ord`）。String の先頭文字のコードポイントを返す `String.ord` の対になるものです。

```ruby
p(Integer.ord(65))           # => 65
p(String.ord("A"))           # => 65
```

# Float

Float は IEEE 754 の倍精度浮動小数点数です。リテラルは `1.5`、`2.0`、`1e-3`（[値と型](../03-values.md)）。文字列からの変換 `Float("1.5")` は Kernel の操作で、Integer からは `Integer.to_f(n)` です。Integer を Float の代わりに渡す暗黙の変換はありません: `Float[1]` や `Float.clamp(x, 1, 2)` は静的に `type` の問題です。

Float に使える演算子は `+`、`-`、`*`、`/`、`%`、`**` と `==`、`!=`、`<`、`<=`、`>`、`>=`、`<=>` です。右側は Integer、Float、Rational、Complex のどれでもよく、結果の型は閉じた表で決まります: Integer・Rational との演算は Float、Complex との演算は Complex（[演算子と添字](../05-operators.md)）。ここに挙げた `Float.+(x, y)` などはその演算子を関数の形で呼ぶもので、左側が Float と決まっている分だけ検査が細かくなります。

Ruby と同じく、0 で割ると例外ではなく `Infinity`・`-Infinity`・`NaN` になり（`%`・`modulo`・`divmod` は例外で `ZeroDivisionError`）、NaN・Infinity を Integer に変える操作（`to_i`、`floor`、`ceil`、`round`、`truncate`、`to_r`、`numerator`、`denominator`）は `FloatDomainError` を投げます。Ruby の `Float::INFINITY` などの定数は、Sake では `Float.INFINITY` のように引数なしの操作として読みます（Sake に値の定数はありません）。Ruby との大きな違いは、`round(f, 2)` が桁数を付けると常に Float を返すこと、負の底に分数の指数（`(-8.0) ** 0.5`）が Complex ではなく `Math::DomainError` になること、`divmod` が Tuple を返すこと、`<=>` と `infinite?` の nil を検査器が追うことです。

## Float[]

`Float[*Any]`

**Float の Array** を作ります（Float そのものではありません）。`Integer[]` などと同じ型付き Array で、要素はすべて Float でなければならず、`Array.push` などの書き込みも毎回検査されます。Integer は Float に変換されません: `Float[1.5, 2]` は静的に `type` の問題、実行時は `TypeError` です。空の Float の Array は `Float[]`。

```ruby
fs = Float[1.5, 2.0]
Array.push(fs, 3.5)
p(fs)                          # => [1.5, 2.0, 3.5]
p(Array.size(Float[]))         # => 0
p(Array.sum(fs))               # => 7.0
```

```ruby error
Array.push(Float[], 1)         # !> Array.push: an element must be Float, but is Integer
```

## INFINITY, NAN, EPSILON, MAX, MIN

`Float.INFINITY()`

`Float.NAN()`

`Float.EPSILON()`

`Float.MAX()`

`Float.MIN()`

Ruby の `Float::INFINITY` などに当たる値を返す、引数なしの操作です（Sake には値の定数が無いので、`Float.INFINITY` または `Float.INFINITY()` と書きます）。`INFINITY` は正の無限大（負は `-Float.INFINITY`）、`NAN` は非数、`EPSILON` は 1.0 と「1.0 より大きい最小の Float」との差、`MAX` は最大の有限値、`MIN` は正の最小の正規化数です。型はすべて Float。NaN はどの値とも `==` で等しくならず、自分自身とも等しくありません。

```ruby
p(Float.INFINITY)              # => Infinity
p(-Float.INFINITY)             # => -Infinity
p(Float.NAN == Float.NAN)      # => false
p(Float.EPSILON)               # => 2.220446049250313e-16
p(1.0 + Float.EPSILON > 1.0)   # => true
p(Float.MAX)                   # => 1.7976931348623157e+308
p(Float.MAX * 2)               # => Infinity
p(Float.MIN)                   # => 2.2250738585072014e-308
```

## +, -, *, /, %, **

`Float.+(x, Any)`

`Float.-(x, Any)`

`Float.*(x, Any)`

`Float./(x, Any)`

`Float.%(x, Any)`

`Float.**(x, Any)`

`x + y` などの関数形で、左側が Float のものです。右側 `y` は Integer、Float、Rational、Complex のどれか。Integer・Rational との結果は Float、Complex との結果は Complex です。それ以外の型（String、nil など）は静的に `type` の問題（`the operands are (Float, String), which the left operand's type does not support`）、実行時は `TypeError` です。

割り算は IEEE に従い、`1.0 / 0` は `Infinity`、`0.0 / 0` は `NaN` で、例外は出ません。`%` は Ruby の `Float#%`（結果の符号は右側に従う）ですが、0（Integer の `0` でも Float の `0.0` でも）で割ると `ZeroDivisionError` です（`rescue` できます。Ruby 4 も同じく投げます）。`**` は Integer・Float・Rational の指数で Float を返します。Ruby と違い、負の底に分数の指数（`(-8.0) ** 0.5`）は Complex ではなく `Math::DomainError` なので、結果は常に Float です。

```ruby
p(1.5 + 2)                     # => 3.5
p(Float.+(1.5, 2r))            # => 3.5
p(Float.+(1.5, Complex(1, 2))) # => (2.5+2i)
p(Float.*(1.5, 2))             # => 3.0
p(Float./(1.0, 0))             # => Infinity
p(Float./(0.0, 0))             # => NaN
p(Float.%(7.5, 2))             # => 1.5
p(-7.5 % 2)                    # => 0.5
p(Float.**(2.0, 3))            # => 8.0
p(Float.**(2.0, 0.5))          # => 1.4142135623730951
p(Float.**(2.0, 2r))           # => 4.0
p((-8.0) ** 2)                 # => 64.0
begin
  7.5 % 0.0
rescue ZeroDivisionError => e
  p(Exception.message(e))      # => "divided by 0"
end
```

```ruby error
p(Float.+(1.5, "a"))           # !> the operands are (Float, String), which the left operand's type does not support
```

```ruby error
p(Float.%(7.5, 0))             # !> ZeroDivisionError: Float.%: divided by 0
```

```ruby error
p(Float.**(-8.0, 0.5))         # !> Math::DomainError: Float.**: -8.0 ** 0.5 is not a real number (a negative base with a fractional exponent)
```

## ==, !=

`Float.==(x, Any)`

`Float.!=(x, Any)`

`x == y` の関数形。Float は Integer・Rational・Complex と値で比べられ、`1.0 == 1` は true です。NaN は自分自身を含むどの値とも等しくありません。別の型の値とは決して等しくなく（`1.0 == "1"` は false）、関数形の `Float.==(x, y)` も演算子と同じく、右側が他のどんな型でも false（`!=` は true）を返し、エラーにはなりません。

```ruby
p(Float.==(1.0, 1))            # => true
p(Float.==(1.0, 1r))           # => true
p(1.5 != 1.5)                  # => false
p(Float.!=(1.0, Float.NAN))    # => true
p(1.0 == "1")                  # => false
p(Float.==(1.0, "1"))          # => false
p(Float.!=(1.0, nil))          # => true
```

## <, <=, >, >=

`Float.<(x, Any)`

`Float.<=(x, Any)`

`Float.>(x, Any)`

`Float.>=(x, Any)`

`x < y` などの関数形。右側は Integer、Float、Rational のどれか（Complex に順序は無く、静的に `type` の問題）。NaN との比較はすべて false です。

```ruby
p(1.5 < 2)                     # => true
p(Float.<=(1.5, 2r))           # => true
p(Float.>(1.5, 2))             # => false
p(Float.>=(1.5, 1.5))          # => true
p(Float.NAN < 1.0)             # => false
```

```ruby error
p(Float.<(1.0, Complex(1, 0))) # !> the operands are (Float, Complex), which the left operand's type does not support
```

## <=>

`Float.<=>(x, Any)`

`x <=> y` の関数形で、-1、0、1 を返します。右側は Integer、Float、Rational。どちらかが NaN なら **nil** なので結果の型は `Integer | nil` で、`--strict`（レベル 2 の `nil`）は結果をそのまま算術に使うことを `the operands may be nil` と報告します。先に `if c` などで確かめてください。

```ruby
p(Float.<=>(1.5, 2))           # => -1
p(1.5 <=> 1.5)                 # => 0
p(Float.<=>(Float.NAN, 1.0))   # => nil
c = 2.0 <=> 1
if c
  p(c + 1)                     # => 2
end
```

```ruby error
c = Float.<=>(1.5, 2.0)
p(c + 1)                       # !> the operands may be nil
```

## abs, magnitude

`Float.abs(x)`

`Float.magnitude(x)`

絶対値（Float）。`-0.0` は `0.0`、`-Infinity` は `Infinity` になります。

```ruby
p(Float.abs(-1.5))             # => 1.5
p(Float.magnitude(-1.5))       # => 1.5
p(Float.abs(-0.0))             # => 0.0
p(Float.abs(-Float.INFINITY))  # => Infinity
```

## negative?, positive?, zero?

`Float.negative?(x)`

`Float.positive?(x)`

`Float.zero?(x)`

`x < 0`、`x > 0`、`x == 0` を true/false で返します。`-0.0` は `zero?` が true で、`negative?` も `positive?` も false です。NaN はどれも false。

```ruby
p(Float.negative?(-1.5))       # => true
p(Float.negative?(-0.0))       # => false
p(Float.positive?(0.0))        # => false
p(Float.zero?(-0.0))           # => true
p(Float.zero?(1.5))            # => false
```

## nan?, finite?, infinite?

`Float.nan?(x)`

`Float.finite?(x)`

`Float.infinite?(x)`

`nan?` は NaN のとき true。`finite?` は NaN でも無限大でもないとき true。`infinite?` は Ruby と同じく正の無限大で `1`、負の無限大で `-1`、それ以外（NaN を含む）で **nil** を返すので、型は `Integer | nil` です。真偽として `if Float.infinite?(x)` のように使うのが普通で、値を算術に使うには先に nil を確かめます（`--strict` の `nil` が報告します）。

```ruby
p(Float.nan?(0.0 / 0))               # => true
p(Float.nan?(1.5))                   # => false
p(Float.finite?(1.5))                # => true
p(Float.finite?(Float.INFINITY))     # => false
p(Float.infinite?(1.5))              # => nil
p(Float.infinite?(Float.INFINITY))   # => 1
p(Float.infinite?(-Float.INFINITY))  # => -1
```

## to_i, to_int, truncate

`Float.to_i(x)`

`Float.to_int(x)`

`Float.truncate(x)`

小数部分を切り捨てて 0 に近い方の Integer にします（Ruby の `Float#to_i`）。3 つは同じ結果です。NaN と Infinity は Integer にできないので `FloatDomainError`（メッセージはその値 `NaN` / `Infinity`）。Ruby の `truncate(digits)` の桁数引数は Float には無く、`Arithmetic.truncate(x, n)` を使います（[Arithmetic](Arithmetic.md)）。

```ruby
p(Float.to_i(1.9))             # => 1
p(Float.to_int(-1.9))          # => -1
p(Float.truncate(-1.8))        # => -1
begin
  Float.to_i(Float.NAN)
rescue FloatDomainError => e
  p(Exception.message(e))      # => "NaN"
end
```

```ruby error
p(Float.truncate(Float.INFINITY))  # !> FloatDomainError: Float.truncate: Infinity
```

## floor, ceil

`Float.floor(x)`

`Float.ceil(x)`

`floor` は x 以下の最大の Integer、`ceil` は x 以上の最小の Integer を返します。NaN・Infinity は `FloatDomainError`。桁数引数は無く、`Arithmetic.floor(x, n)`・`Arithmetic.ceil(x, n)` が代わりです。

```ruby
p(Float.floor(1.8))            # => 1
p(Float.floor(-1.2))           # => -2
p(Float.ceil(1.2))             # => 2
p(Float.ceil(-1.2))            # => -1
```

```ruby error
p(Float.floor(Float.INFINITY)) # !> FloatDomainError: Float.floor: Infinity
```

## round

`Float.round(x, [Integer], [half: Symbol])`

四捨五入します。桁数を省くと最も近い Integer を返し、.5 は既定では 0 から遠い方に丸めます（`Float.round(2.5)` は 3、`-2.5` は -3。Ruby の `round` と同じ）。桁数 `n` を付けると小数第 n 位に丸めた **Float** を返します。負の桁数は 10 の冪に丸めますが、結果はやはり Float です（Ruby の `1234.5.round(-2)` は Integer 1200 ですが、Sake では `1200.0`）。結果の型が桁数の有無で決まるのは、検査器が引数の個数を見るからです。キーワード `half:` は Ruby と同じく、ちょうど .5 のときの丸め方を選びます: `:up`（既定。0 から遠い方へ）、`:even`（偶数側へ。銀行家の丸め）、`:down`（0 に近い方へ）。他の Symbol は `ArgumentError`（`invalid rounding mode: foo`）、Symbol 以外は `type` の問題です。桁数なしの NaN・Infinity は `FloatDomainError`、桁数付きならそのまま NaN・Infinity を返します。

```ruby
p(Float.round(1.5))            # => 2
p(Float.round(2.5))            # => 3
p(Float.round(-2.5))           # => -3
p(Float.round(1.2345, 2))      # => 1.23
p(Float.round(3.14159, 3))     # => 3.142
p(Float.round(1234.5, -2))     # => 1200.0
p(Float.round(1.5, 0))         # => 2.0
p(Float.round(Float.NAN, 2))   # => NaN
p(Float.round(2.5, half: :even))      # => 2
p(Float.round(3.5, half: :even))      # => 4
p(Float.round(2.5, half: :down))      # => 2
p(Float.round(2.5, 0, half: :even))   # => 2.0
p(Float.round(1.25, 1, half: :even))  # => 1.2
p(Float.round(1250.0, -2, half: :even))  # => 1200.0
```

```ruby error
p(Float.round(-Float.INFINITY))  # !> FloatDomainError: Float.round: -Infinity
```

```ruby error
p(Float.round(2.5, half: :foo))  # !> ArgumentError: Float.round: invalid rounding mode: foo
```

## divmod

`Float.divmod(x, Any)`

商と余りの Tuple `[q, r]` を返します。`q` は `x / y` を floor した **Integer**、`r` は `x - q * y` の Float で、符号は `y` に従います（Ruby の `7.5.divmod(2)` が `[3, 1.5]` なのと同じ）。`y` は Float か Integer で、他の型（Rational を含む）は静的に `type` の問題です。0（Integer の `0` でも Float の `0.0` でも）で割ると `ZeroDivisionError`、`x` が NaN・Infinity なら `FloatDomainError`（メッセージはその値）です。どちらも `rescue` できます。

```ruby
p(Float.divmod(7.5, 2))        # => [3, 1.5]
p(Float.divmod(-7.5, 2.0))     # => [-4, 0.5]
q, r = Float.divmod(7.5, 2)
p(q + 1)                       # => 4
p(r + 0.5)                     # => 2.0
begin
  Float.divmod(Float.NAN, 2)
rescue FloatDomainError => e
  p(Exception.message(e))      # => "NaN"
end
```

```ruby error
p(Float.divmod(7.5, 0))        # !> ZeroDivisionError: Float.divmod: divided by 0
```

```ruby error
p(Float.divmod(7.5, 0.0))      # !> ZeroDivisionError: Float.divmod: divided by 0
```

## fdiv, quo

`Float.fdiv(x, Integer|Float|Rational)`

`Float.quo(x, Integer|Float|Rational)`

浮動小数点の割り算 `x / y`（Float）。`/` と同じ結果で、0 で割れば `Infinity` か `NaN` です（例外は出ません）。2 つは同じ働きです。

```ruby
p(Float.fdiv(7.5, 2))          # => 3.75
p(Float.quo(1.0, 4r))          # => 0.25
p(Float.fdiv(1.0, 0))          # => Infinity
```

## modulo

`Float.modulo(x, Integer|Float|Rational)`

`x % y` と同じ余り（Float。符号は `y` に従う）で、`%` と同じ働きです。0（Integer の 0 でも `0.0` でも）で割ると `ZeroDivisionError` を投げます。

```ruby
p(Float.modulo(7.5, 2))        # => 1.5
p(Float.modulo(-7.5, 2))       # => 0.5
p(Float.modulo(5.5, 2.5))      # => 0.5
begin
  Float.modulo(7.5, 0)
rescue ZeroDivisionError => e
  p(Exception.message(e))      # => "divided by 0"
end
```

## between?

`Float.between?(x, Float, Float)`

`lo <= x <= hi` のとき true。`lo`、`hi` は Float でなければならず、Integer は静的に `type` の問題です（`argument 2 must be Float, but is Integer`）。

```ruby
p(Float.between?(1.5, 1.0, 2.0))   # => true
p(Float.between?(2.5, 1.0, 2.0))   # => false
```

```ruby error
p(Float.between?(1.5, 1, 2))       # !> Float.between?: argument 2 must be Float, but is Integer
```

## clamp

`Float.clamp(x, Float, Float)`

`x` を `lo..hi` に収めた Float を返します（`lo` 未満なら `lo`、`hi` より大きければ `hi`）。`lo`、`hi` は Float のみ。`lo > hi` は `ArgumentError`（`min argument must be less than or equal to max argument`）で、`rescue` できます。

```ruby
p(Float.clamp(2.5, 1.0, 2.0))  # => 2.0
p(Float.clamp(0.5, 1.0, 2.0))  # => 1.0
p(Float.clamp(1.5, 1.0, 2.0))  # => 1.5
```

```ruby error
p(Float.clamp(1.5, 1, 2))      # !> Float.clamp: argument 2 must be Float, but is Integer
```

```ruby error
p(Float.clamp(1.5, 2.0, 1.0))  # !> ArgumentError: Float.clamp: min argument must be less than or equal to max argument
```

## next_float, prev_float

`Float.next_float(x)`

`Float.prev_float(x)`

x の次に大きい・次に小さい表現可能な Float。`next_float(1.0) - 1.0` が `Float.EPSILON` です。`Float.MAX` の次は `Infinity`、NaN の次は NaN。

```ruby
p(Float.next_float(1.0))                       # => 1.0000000000000002
p(Float.prev_float(1.0))                       # => 0.9999999999999999
p(Float.next_float(0.0))                       # => 5.0e-324
p(Float.next_float(1.0) - 1.0 == Float.EPSILON)  # => true
p(Float.next_float(Float.MAX))                 # => Infinity
```

## to_r, rationalize

`Float.to_r(x)`

`Float.rationalize(x)`

Rational に変えます。`to_r` は 2 進の値をそのまま分数にするので `0.1` は `3602879701896397/36028797018963968` になります。`rationalize` は元の Float に丸め戻せる範囲で最も簡単な分数を選ぶので `0.1` は `1/10` です。NaN・Infinity は `FloatDomainError`。Ruby の `rationalize(eps)` の許容誤差引数は Float には無く、`Rational.rationalize(r, eps)` が代わりです（[Rational](Rational.md)）。

```ruby
p(Float.to_r(0.75))            # => (3/4)
p(Float.to_r(0.1))             # => (3602879701896397/36028797018963968)
p(Float.rationalize(0.1))      # => (1/10)
p(Float.rationalize(0.333))    # => (333/1000)
p(Float.to_r(-1.5))            # => (-3/2)
```

```ruby error
p(Float.to_r(Float.NAN))       # !> FloatDomainError: Float.to_r: NaN
```

## numerator, denominator

`Float.numerator(x)`

`Float.denominator(x)`

`Float.to_r(x)` の分子・分母（Integer）。`0.1` の分母は `36028797018963968` のように 2 進表現の値になります。Ruby では NaN の `numerator` は NaN そのもの、`denominator` は 1 ですが、Sake では NaN・Infinity は `FloatDomainError` で、結果は常に Integer です。

```ruby
p(Float.numerator(0.75))       # => 3
p(Float.denominator(0.75))     # => 4
p(Float.numerator(1.5))        # => 3
p(Float.denominator(0.1))      # => 36028797018963968
```

```ruby error
p(Float.numerator(Float.NAN))  # !> FloatDomainError: Float.numerator: NaN
```

## angle, arg, phase

`Float.angle(x)`

`Float.arg(x)`

`Float.phase(x)`

複素平面での偏角。正の数（と `0.0`）では Integer の `0`、負の数（と `-0.0`）では Float の `π` を返すので、型は `Integer | Float` です。NaN では NaN。3 つは同じ働きです。

```ruby
p(Float.angle(1.5))            # => 0
p(Float.arg(-1.5))             # => 3.141592653589793
p(Float.phase(-0.0))           # => 3.141592653589793
p(Float.angle(Float.NAN))      # => NaN
```

## to_f, to_s

`Float.to_f(x)`

`Float.to_s(x)`

`to_f` は x 自身を返します（型が `Integer | Float` の値をまとめて Float にするには `Arithmetic.to_f(x)`）。`to_s` は Ruby の表記で、整数値でも `.0` が付き、おおよそ 1e16 以上と 1e-4 未満は `1.0e+20` のような指数表記になります。`Infinity`、`-Infinity`、`NaN` もそのまま文字にします。`puts(1.5)` も同じ表記です。

```ruby
p(Float.to_f(1.5))             # => 1.5
p(Float.to_s(1.0))             # => "1.0"
p(Float.to_s(0.1 + 0.2))       # => "0.30000000000000004"
p(Float.to_s(1e20))            # => "1.0e+20"
p(Float.to_s(1e-5))            # => "1.0e-05"
p(Float.to_s(Float.INFINITY))  # => "Infinity"
p(Float.to_s(-0.0))            # => "-0.0"
```

# Rational

Rational は分子と分母が Integer の有理数で、常に既約で表されます。リテラルは Ruby と同じ `2r`、`1/3r`（`1 / 3r` の割り算）、`0.5r`（`1/2`）で、`Rational(1, 3)`・`Rational("1/3")`・`Rational(0.5)`（Ruby と同じく `(1/2)`）は Kernel の操作です（Float からは `Float.to_r`・`Float.rationalize` でも変換できます。[値と型](../03-values.md)）。Rational の値を `p` で表示すると `(1/3)` の形になります。

Rational に使える演算子は `+`、`-`、`*`、`/`、`%`、`**` と `==`、`!=`、`<`、`<=`、`>`、`>=`、`<=>` です。右側は Integer、Float、Rational、Complex のどれでもよく、結果の型は閉じた表で決まります: Integer との演算は Rational、Float との演算は Float、Complex との演算は Complex（[演算子と添字](../05-operators.md)）。`1 + 1r/2` のように Integer が左でも Rational になります。Integer の負の冪 `2 ** -1` は Ruby なら Rational ですが Sake では `ArgumentError` で、`2r ** -1` と書きます。ここに挙げた `Rational.+(x, y)` などはその演算子を関数の形で呼ぶものです。

Ruby と同じく、Rational を 0 で割ると `ZeroDivisionError` です（Float と違い、無限大にはなりません）。Ruby との違いは、`round`・`floor`・`ceil`・`truncate` に桁数引数が無いこと（`Arithmetic.round(r, n)` を使います。[Arithmetic](Arithmetic.md)）、`quo` と `rationalize` の引数が Float を取らないことです。

## Rational[]

`Rational[*Any]`

**Rational の Array** を作ります（Rational そのものではありません）。要素はすべて Rational でなければならず、`Array.push` などの書き込みも毎回検査されます。Integer は Rational に変換されず、静的に `type` の問題、実行時は `TypeError` です。空の Rational の Array は `Rational[]`。

```ruby
rs = Rational[1r/2, 2r]
Array.push(rs, Rational(1, 3))
p(rs)                            # => [(1/2), (2/1), (1/3)]
p(Array.size(Rational[]))        # => 0
```

```ruby error
Array.push(Rational[], 1)        # !> Array.push: an element must be Rational, but is Integer
```

## +, -, *, /, %, **

`Rational.+(x, Any)`

`Rational.-(x, Any)`

`Rational.*(x, Any)`

`Rational./(x, Any)`

`Rational.%(x, Any)`

`Rational.**(x, Any)`

`x + y` などの関数形で、左側が Rational のものです。右側 `y` は Integer、Float、Rational、Complex のどれか。Integer・Rational との結果は Rational、Float との結果は Float、Complex との結果は Complex です。それ以外の型は静的に `type` の問題、実行時は `TypeError`。`/` と `%` の右側が 0（`0`・`0r`）なら `ZeroDivisionError`（`0.0` なら Float の規則で `Infinity`）。`%` は Ruby の `Rational#%` で、結果の符号は右側に従います。`**` は Integer の指数なら Rational（負でもよく、`2r ** -1` は `(1/2)`）、Float の指数なら Float です。**Rational の指数**では、整数値なら Rational（`4r ** 2r` は `(16/1)`）、そうでなければ Float（`4r ** (1r/2)` は `2.0`）になるので、検査器はその結果を `Rational | Float` とします。どちらかとして使う前に `case`/`in` で絞ってください（`Rational.numerator(4r ** 2r)` は `type` の問題）。負の底に分数の指数は `Math::DomainError` です（Ruby は Complex を返す）。

```ruby
p(1r/3 + 1r/6)                   # => (1/2)
p(Rational.+(1r/3, 1))           # => (4/3)
p(Rational.+(1r/3, 0.5))         # => 0.8333333333333333
p(Rational.+(1r/3, Complex(1, 1)))  # => ((4/3)+1i)
p(Rational.-(1r, 1r/3))          # => (2/3)
p(Rational.*(2r/3, 3r/4))        # => (1/2)
p(Rational./(1r/3, 2))           # => (1/6)
p(Rational.%(7r/3, 1r/2))        # => (1/3)
p(Rational.**(2r, -1))           # => (1/2)
p(Rational.**(1r/2, 3))          # => (1/8)
p(Rational.**(4r, 2r))           # => (16/1)
p(Rational.**(2r, 1r/2))         # => 1.4142135623730951
x = 4r ** (1r/2)
case x
in Rational then p(Rational.numerator(x))
in Float then p(x)               # => 2.0
end
```

```ruby error
p(Rational./(1r, 0))             # !> ZeroDivisionError: Rational./: divided by 0
```

```ruby error
p(Rational.numerator(4r ** 2r))  # !> Rational.numerator: argument 1 must be Rational, but can be Float
```

```ruby error
p((-8r) ** (1r/2))               # !> Math::DomainError: Arithmetic.**: -8/1 ** 1/2 is not a real number (a negative base with a fractional exponent)
```

## ==, !=

`Rational.==(x, Any)`

`Rational.!=(x, Any)`

`x == y` の関数形。Rational は Integer・Float・Complex と値で比べられ、`1r/2 == 0.5` も `2r == 2` も true です。別の型の値とは決して等しくなく、関数形の `Rational.==(x, y)` も演算子と同じく、右側が他のどんな型でも false（`!=` は true）を返し、エラーにはなりません。

```ruby
p(Rational.==(1r/2, 0.5))        # => true
p(Rational.==(2r, 2))            # => true
p(Rational.!=(1r/2, 1r/3))       # => true
p(1r == nil)                     # => false
p(Rational.==(1r/2, "x"))        # => false
p(Rational.!=(1r/2, "x"))        # => true
```

## <, <=, >, >=

`Rational.<(x, Any)`

`Rational.<=(x, Any)`

`Rational.>(x, Any)`

`Rational.>=(x, Any)`

`x < y` などの関数形。右側は Integer、Float、Rational のどれか（Complex に順序は無く、静的に `type` の問題）。Rational 同士・Integer との比較は正確で、Float とは Float の値で比べます。

```ruby
p(1r/3 < 1r/2)                   # => true
p(Rational.<(1r/3, 0.5))         # => true
p(Rational.<=(1r/2, 0.5))        # => true
p(Rational.>(1r/3, 0.3))         # => true
p(Rational.>=(1r, 1))            # => true
```

```ruby error
p(Rational.<(1r, Complex(1, 0))) # !> the operands are (Rational, Complex), which the left operand's type does not support
```

## <=>

`Rational.<=>(x, Any)`

`x <=> y` の関数形で、-1、0、1 を返します。右側が Integer か Rational なら結果は常に Integer です。右側が Float のときは NaN なら **nil** になるので型は `Integer | nil` で、`--strict`（レベル 2 の `nil`）は結果をそのまま算術に使うことを報告します。

```ruby
p(Rational.<=>(1r/3, 1r/2))      # => -1
p(Rational.<=>(1r/2, 1r/2))      # => 0
p(Rational.<=>(1r, 1r/2))        # => 1
p(Rational.<=>(1r/2, Float.NAN)) # => nil
c = Rational.<=>(1r/3, 1r/2)
p(c + 1)                         # => 0
```

```ruby error
c = Rational.<=>(1r/3, 0.5)
p(c + 1)                         # !> the operands may be nil
```

## abs, magnitude

`Rational.abs(x)`

`Rational.magnitude(x)`

絶対値（Rational）。2 つは同じ働きです。

```ruby
p(Rational.abs(-1r/3))           # => (1/3)
p(Rational.magnitude(-1r/3))     # => (1/3)
p(Rational.abs(-5r/2))           # => (5/2)
```

## negative?, positive?, zero?

`Rational.negative?(x)`

`Rational.positive?(x)`

`Rational.zero?(x)`

`x < 0`、`x > 0`、`x == 0` を true/false で返します。

```ruby
p(Rational.positive?(1r/3))      # => true
p(Rational.positive?(0r))        # => false
p(Rational.negative?(-1r/3))     # => true
p(Rational.zero?(0r))            # => true
p(Rational.zero?(1r/3))          # => false
```

## numerator, denominator

`Rational.numerator(x)`

`Rational.denominator(x)`

既約分数にしたときの分子・分母（Integer）。符号は分子が持ち、分母は常に正です。整数値の分母は 1。

```ruby
p(Rational.numerator(-6r/4))     # => -3
p(Rational.denominator(-6r/4))   # => 2
p(Rational.numerator(1r/2 + 1r/2))    # => 1
p(Rational.denominator(1r/2 + 1r/2))  # => 1
```

## to_i, truncate, floor, ceil, round

`Rational.to_i(x)`

`Rational.truncate(x)`

`Rational.floor(x)`

`Rational.ceil(x)`

`Rational.round(x)`

Integer にします。`to_i` と `truncate` は 0 に近い方へ、`floor` は下へ、`ceil` は上へ、`round` は最も近い Integer へ（ちょうど .5 は 0 から遠い方へ: `Rational.round(5r/2)` は 3、`-5r/2` は -3）。Ruby の `round(digits)` などの桁数引数はこれらには無く、桁を指定するには `Arithmetic.round(x, n)` を使います（結果は Rational）。

```ruby
p(Rational.to_i(-7r/2))          # => -3
p(Rational.truncate(7r/3))       # => 2
p(Rational.floor(-7r/2))         # => -4
p(Rational.ceil(7r/2))           # => 4
p(Rational.round(7r/2))          # => 4
p(Rational.round(5r/2))          # => 3
p(Rational.round(-1r/2))         # => -1
```

```ruby error
p(Rational.round(7r/3, 1))       # !> wrong number of arguments for Rational.round (given 2, expected 1)
```

## fdiv

`Rational.fdiv(x, Integer|Float|Rational)`

浮動小数点の割り算 `x / y` の結果を **Float** で返します。0 で割ると `Infinity`（例外は出ません）。

```ruby
p(Rational.fdiv(1r/3, 2))        # => 0.16666666666666666
p(Rational.fdiv(2r/3, 1r/3))     # => 2.0
p(Rational.fdiv(1r, 0))          # => Infinity
```

## quo

`Rational.quo(x, Integer|Rational)`

正確な割り算 `x / y`（Rational）。`y` は Integer か Rational で、Float は静的に `type` の問題です（Float で割るには `/` を使います）。0 で割ると `ZeroDivisionError`。

```ruby
p(Rational.quo(1r/3, 2))         # => (1/6)
p(Rational.quo(1r/3, 2r/3))      # => (1/2)
```

```ruby error
p(Rational.quo(1r/3, 0))         # !> ZeroDivisionError: Rational.quo: divided by 0
```

## rationalize

`Rational.rationalize(x, [Rational])`

許容誤差 `eps`（Rational）の範囲 `x - eps .. x + eps` で最も簡単な分数を返します（Ruby の `Rational#rationalize`）。`eps` を省くと x 自身を返します。`eps` は Rational でなければならず、Float は静的に `type` の問題です。

```ruby
pi = 3141592653589793r/1000000000000000
p(Rational.rationalize(pi, 1r/100))   # => (22/7)
p(Rational.rationalize(pi, 1r/1000000))  # => (355/113)
p(Rational.rationalize(1r/3))         # => (1/3)
```

```ruby error
p(Rational.rationalize(1r/3, 0.1))    # !> Rational.rationalize: argument 2 must be Rational, but is Float
```

## to_f

`Rational.to_f(x)`

最も近い Float にします。

```ruby
p(Rational.to_f(1r/4))           # => 0.25
p(Rational.to_f(2r/3))           # => 0.6666666666666666
```

## to_r

`Rational.to_r(x)`

x 自身を返します（型が `Integer | Rational` の値をまとめて扱うときの形合わせ用）。

```ruby
p(Rational.to_r(1r/3))           # => (1/3)
```

## to_s

`Rational.to_s(x)`

`"分子/分母"` の形の String（Ruby と同じ）。整数値でも `"2/1"` と分母が付きます。`p` の表示 `(1/3)` とは括弧の分だけ違います。

```ruby
p(Rational.to_s(1r/3))           # => "1/3"
p(Rational.to_s(2r))             # => "2/1"
p(Rational.to_s(-6r/4))          # => "-3/2"
```

# Complex

Complex は実部と虚部を持つ複素数で、各部は Integer、Float、Rational のどれかです。リテラルは Ruby と同じ虚数単位の `2i`、`3.5i` と、それを使った `1 + 2i` で、`Complex(1, 2)`（虚部省略で `Complex(1.5)`）は Kernel の操作です（引数は実数のみ。[値と型](../03-values.md)）。`p` で表示すると `(1+2i)` の形になります。

Complex に使える演算子は `+`、`-`、`*`、`/`、`**` と `==`、`!=` です。Complex には順序が無いので `<` などの比較は無く、`%` もありません（静的に `type` の問題）。右側は Integer、Float、Rational、Complex のどれでもよく、結果は常に Complex です。Integer・Float・Rational が左側でも、右側が Complex なら結果は Complex です（[演算子と添字](../05-operators.md)）。ここに挙げた `Complex.+(x, y)` などはその演算子を関数の形で呼ぶものです。

各部の型は値の中に残り、`Complex(1, 2) / 2` は `((1/2)+1i)` と Rational の実部になります（Ruby と同じ）。実部・虚部を取り出す `real`・`imag` の結果の型が `Integer | Float | Rational` なのはそのためで、Integer として使うには `case`/`in` などで型を確かめます。Ruby との違いは、各部に Complex を渡せないことです。

## Complex[]

`Complex[*Any]`

**Complex の Array** を作ります（Complex そのものではありません）。要素はすべて Complex でなければならず、`Array.push` などの書き込みも毎回検査されます。実数は Complex に変換されず、静的に `type` の問題、実行時は `TypeError` です。空の Complex の Array は `Complex[]`。

```ruby
cs = Complex[Complex(1, 2), 3i]
Array.push(cs, Complex(0, 0))
p(cs)                              # => [(1+2i), (0+3i), (0+0i)]
p(Array.size(Complex[]))           # => 0
```

```ruby error
Array.push(Complex[], 1)           # !> Array.push: an element must be Complex, but is Integer
```

## +, -, *, /, **

`Complex.+(x, Any)`

`Complex.-(x, Any)`

`Complex.*(x, Any)`

`Complex./(x, Any)`

`Complex.**(x, Any)`

`x + y` などの関数形で、左側が Complex のものです。右側 `y` は Integer、Float、Rational、Complex のどれかで、結果は Complex。他の型は静的に `type` の問題、実行時は `TypeError` です。`/` は各部の型に従って正確に計算し、Integer 同士の部は Rational になります。各部がすべて正確（Integer・Rational）な Complex を 0 や `Complex(0, 0)` で割ると `ZeroDivisionError`、Float の部を含んでいても Integer の 0 で割れば同じく `ZeroDivisionError` ですが、`0.0` で割ると Float の規則で `Infinity` の部になります（Ruby と同じ）。`**` は整数乗なら正確、それ以外は Float の部になります。`%` は Complex にありません。

```ruby
c = Complex(1, 2)
p(c + Complex(3, 4))               # => (4+6i)
p(Complex.+(c, 1.5))               # => (2.5+2i)
p(Complex.-(Complex(5, 3), 2))     # => (3+3i)
p(Complex.*(c, c))                 # => (-3+4i)
p(Complex.*(Complex(1, 1), Complex(1, -1)))  # => (2+0i)
p(Complex./(c, 2))                 # => ((1/2)+1i)
p(Complex./(Complex(1.0, 2), 2))   # => (0.5+1i)
p(Complex./(Complex(1, 2), 0.0))   # => (Infinity+Infinity*i)
p(Complex.**(Complex(0, 1), 2))    # => (-1+0i)
p(Complex.**(c, -1))               # => ((1/5)-(2/5)*i)
p(1.5 * c)                         # => (1.5+3.0i)
```

```ruby error
p(Complex./(Complex(1, 2), 0))     # !> ZeroDivisionError: Complex./: divided by 0
```

## ==, !=

`Complex.==(x, Any)`

`Complex.!=(x, Any)`

`x == y` の関数形。実部と虚部がそれぞれ `==` なら true で、`Complex(1, 0) == 1` や `Complex(1.0, 0) == 1` も true です。別の型の値とは決して等しくなく（`Complex(1, 2) == "x"` は false）、関数形の `Complex.==(x, y)` も演算子と同じく、右側が他のどんな型でも false（`!=` は true）を返し、エラーにはなりません。

```ruby
p(Complex.==(Complex(1, 2), Complex(1, 2)))    # => true
p(Complex.==(Complex(1, 0), 1))                # => true
p(Complex.==(Complex(2, 0), 2.0))              # => true
p(Complex.!=(Complex(1, 2), Complex(2, 1)))    # => true
p(Complex(1, 2) == "x")                        # => false
p(Complex.==(Complex(1, 2), "x"))              # => false
p(Complex.==(Complex(1, 2), nil))              # => false
```

## real, imag, imaginary

`Complex.real(x)`

`Complex.imag(x)`

`Complex.imaginary(x)`

実部・虚部を返します。型は作ったときの部の型（`Integer | Float | Rational`）です。`imag` と `imaginary` は同じ働きです。

```ruby
c = Complex(1, 2.5)
p(Complex.real(c))                 # => 1
p(Complex.imag(c))                 # => 2.5
p(Complex.imaginary(Complex(3, 4))) # => 4
p(Complex.real(Complex(1r/2, 1)))  # => (1/2)
r = Complex.real(Complex(1, 2))
p(r + 1)                           # => 2
```

## rect, rectangular

`Complex.rect(x)`

`Complex.rectangular(x)`

実部と虚部の Tuple `[re, im]`（各位置の型は `Integer | Float | Rational`）。多重代入で両方を受け取れます。2 つは同じ働きです。

```ruby
p(Complex.rect(Complex(1, 2)))             # => [1, 2]
p(Complex.rectangular(Complex(1.5, 2r)))   # => [1.5, (2/1)]
re, im = Complex.rectangular(Complex(1, 2))
p(re + im)                                 # => 3
```

## polar

`Complex.polar(x)`

極形式の Tuple `[r, θ]`。`r` は `abs` とまったく同じ絶対値（`Integer | Float`。Rational の絶対値は Float になり、`Complex.polar(Complex(3r, 0))` は `[3.0, 0.0]`）、`θ` は偏角（`arg` と同じ Float。実軸上の値では `0.0`・`π`）です。

```ruby
p(Complex.polar(Complex(3, 4)))    # => [5.0, 0.9272952180016122]
p(Complex.polar(Complex(0, 2)))    # => [2, 1.5707963267948966]
p(Complex.polar(Complex(-2, 0)))   # => [2, 3.141592653589793]
p(Complex.polar(Complex(3r, 0)))   # => [3.0, 0.0]
r, th = Complex.polar(Complex(3, 4))
p(r)                               # => 5.0
```

## abs, magnitude

`Complex.abs(x)`

`Complex.magnitude(x)`

絶対値 `sqrt(re² + im²)`。普通は Float ですが、Ruby と同じく片方の部が正確な 0 ならもう一方の部の絶対値をそのまま返すので、`Complex(3, 0)` では Integer の `3` です。Ruby と違い、Rational の絶対値は Float になります（`Complex.abs(Complex(3r, 0))` は `3.0`）。型はちょうど `Integer | Float` です。2 つは同じ働きです。

```ruby
p(Complex.abs(Complex(3, 4)))      # => 5.0
p(Complex.abs(Complex(3, 0)))      # => 3
p(Complex.abs(Complex(0, -2)))     # => 2
p(Complex.abs(Complex(3r, 0)))     # => 3.0
p(Complex.magnitude(Complex(1, 1))) # => 1.4142135623730951
a = Complex.abs(Complex(3, 4))
p(a + 1)                           # => 6.0
```

## abs2

`Complex.abs2(x)`

絶対値の 2 乗 `re² + im²`。平方根を取らないので正確で、型は各部に従う `Integer | Float | Rational` です。

```ruby
p(Complex.abs2(Complex(3, 4)))         # => 25
p(Complex.abs2(Complex(1.5, 0)))       # => 2.25
p(Complex.abs2(Complex(1r/2, 1r/2)))   # => (1/2)
```

## arg, angle, phase

`Complex.arg(x)`

`Complex.angle(x)`

`Complex.phase(x)`

偏角（Float、`-π` から `π`）。`Math.atan2(im, re)` と同じで、`Complex(0, 0)` では `0.0`、負の実軸上では `π` です。3 つは同じ働きです。

```ruby
p(Complex.arg(Complex(1, 1)))      # => 0.7853981633974483
p(Complex.angle(Complex(0, 1)))    # => 1.5707963267948966
p(Complex.phase(Complex(-1, 0)))   # => 3.141592653589793
p(Complex.arg(Complex(0, -1)))     # => -1.5707963267948966
p(Complex.arg(Complex(0, 0)))      # => 0.0
```

## conj, conjugate

`Complex.conj(x)`

`Complex.conjugate(x)`

共役複素数（虚部の符号を反転した Complex）。2 つは同じ働きです。

```ruby
p(Complex.conj(Complex(1, 2)))         # => (1-2i)
p(Complex.conjugate(Complex(1.5, -2))) # => (1.5+2i)
p(Complex.conjugate(Complex(3, 0)))    # => (3+0i)
```

## real?

`Complex.real?(x)`

常に **false** を返します（Ruby の `Complex#real?` と同じく、Complex という型は虚部が 0 でも実数ではないとみなします）。実数かどうかを値で知るには `Complex.imag(x) == 0` を使います。

```ruby
p(Complex.real?(Complex(1, 2)))    # => false
p(Complex.real?(Complex(1, 0)))    # => false
p(Complex.imag(Complex(1, 0)) == 0)  # => true
```

## finite?, infinite?

`Complex.finite?(x)`

`Complex.infinite?(x)`

`finite?` は実部と虚部がともに有限（NaN でも無限大でもない）のとき true。`infinite?` は Ruby と同じく、どちらかの部が無限大なら `1`、そうでなければ **nil**（NaN を含む）を返すので型は `Integer | nil` です。真偽として使うのが普通で、値を算術に使うには先に nil を確かめます（`--strict` の `nil` が報告します）。

```ruby
p(Complex.finite?(Complex(1, 2)))                 # => true
p(Complex.finite?(Complex(Float.INFINITY, 2)))    # => false
p(Complex.finite?(Complex(Float.NAN, 2)))         # => false
p(Complex.infinite?(Complex(1, 2)))               # => nil
p(Complex.infinite?(Complex(1, -Float.INFINITY))) # => 1
p(Complex.infinite?(Complex(Float.NAN, 2)))       # => nil
```

```ruby error
x = Complex.infinite?(Complex(1, 2))
p(x + 1)                           # !> the operands may be nil
```

## fdiv

`Complex.fdiv(x, Integer|Float|Rational)`

各部を Float にしてから実数 `y` で割った Complex（各部は Float）。`y` に Complex は渡せません（静的に `type` の問題。Complex で割るには `/` か `quo`）。0 で割ると `Infinity` の部になり、例外は出ません。

```ruby
p(Complex.fdiv(Complex(3, 4), 2))    # => (1.5+2.0i)
p(Complex.fdiv(Complex(1, 2), 2r))   # => (0.5+1.0i)
p(Complex.fdiv(Complex(1, 2), 0))    # => (Infinity+Infinity*i)
```

```ruby error
p(Complex.fdiv(Complex(1, 2), Complex(1, 1)))  # !> Complex.fdiv: argument 2 must be Integer|Float|Rational, but is Complex
```

## quo

`Complex.quo(x, Integer|Float|Rational|Complex)`

割り算 `x / y`（Complex）。`/` と同じで、Integer 同士の部は Rational になります。正確な 0 で割ると `ZeroDivisionError`。

```ruby
p(Complex.quo(Complex(3, 4), 2))              # => ((3/2)+2i)
p(Complex.quo(Complex(3, 4), 2.0))            # => (1.5+2.0i)
p(Complex.quo(Complex(3, 4), Complex(1, 1)))  # => ((7/2)+(1/2)*i)
```

```ruby error
p(Complex.quo(Complex(1, 2), 0))   # !> ZeroDivisionError: Complex.quo: divided by 0
```

## numerator, denominator

`Complex.numerator(x)`

`Complex.denominator(x)`

`denominator` は実部と虚部の分母の最小公倍数（Integer）、`numerator` は `x * denominator`（各部が整数になった Complex）です。Integer の部の分母は 1。

```ruby
c = Complex(1r/2, 1r/4)
p(Complex.denominator(c))          # => 4
p(Complex.numerator(c))            # => (2+1i)
p(Complex.denominator(Complex(3, 4)))  # => 1
p(Complex.numerator(Complex(3, 4)))    # => (3+4i)
```

## to_i, to_f, to_r, rationalize

`Complex.to_i(x)`

`Complex.to_f(x)`

`Complex.to_r(x)`

`Complex.rationalize(x, [Rational])`

虚部が正確な 0（Integer の `0` か `0r`）のときだけ、実部を Integer・Float・Rational にします（`rationalize` は実部の `rationalize`。許容誤差 `eps` は Rational）。虚部が 0 でないとき、または `0.0`（Float の 0）のときは `RangeError`（メッセージは Ruby のもの: `can't convert 1+2i into Float`）を投げ、`rescue` できます。

```ruby
p(Complex.to_i(Complex(1.9, 0)))           # => 1
p(Complex.to_f(Complex(3, 0)))             # => 3.0
p(Complex.to_r(Complex(1.5, 0)))           # => (3/2)
p(Complex.rationalize(Complex(0.333, 0)))  # => (333/1000)
p(Complex.rationalize(Complex(0.333, 0), 1r/100))  # => (1/3)
begin
  Complex.to_f(Complex(1, 2))
rescue RangeError => e
  p(Exception.message(e))                  # => "can't convert 1+2i into Float"
end
```

```ruby error
p(Complex.to_f(Complex(1, 0.0)))   # !> RangeError: Complex.to_f: can't convert 1+0.0i into Float
```

## to_c

`Complex.to_c(x)`

x 自身を返します（実数を Complex にするのは Kernel の `Complex(x)`）。

```ruby
p(Complex.to_c(Complex(3, 4)))     # => (3+4i)
```

## to_s

`Complex.to_s(x)`

`"re+imi"` の形の String（Ruby と同じ）。`p` の表示 `(3+4i)` から括弧を外したもので、Rational の部は `1/2+3i` のように括弧なしです。

```ruby
p(Complex.to_s(Complex(3, 4)))         # => "3+4i"
p(Complex.to_s(Complex(-1, -1)))       # => "-1-1i"
p(Complex.to_s(Complex(0.5, 2)))       # => "0.5+2i"
p(Complex.to_s(Complex(1r/2, 3)))      # => "1/2+3i"
```

# Arithmetic

Arithmetic は算術演算子 `+`、`-`、`*`、`/`、`%`、`**` と単項の `-x`、`+x` が属するモジュールです。`a + b` は `Arithmetic.+(a, b)` の略記で、左側の値の型（Integer、Float、Rational、Complex、String、Time、Set、または `include Arithmetic` したクラス）の `+` に振り分けられます（[演算子と添字](../05-operators.md)、[プログラムの構造](../02-program.md)）。

この章に挙げる 8 つの操作は、演算子ではなく、**どの実数（Integer、Float、Rational）にも使える丸めと変換**です。Sake の操作は普通 `Float.round(f)` のように型を名乗りますが、値の型が `Integer | Float` のように定まらないとき（`Array.sum` の結果、JSON から読んだ数など）に、Ruby の `x.round` と同じく値の型を見て振り分けるのがこれらです。結果の型は引数の型に従います: 桁数なしの `round`・`floor`・`ceil`・`truncate` と `to_i` は Integer、桁数付きの丸めと `abs` は引数と同じ型（引数の型が和なら結果も和）、`to_f` は Float、`zero?` は true/false。検査器は引数の各型についてこの規則を当てます。

引数が Complex や String なら静的に `type` の問題です（`argument 1 must be Integer|Float|Rational, but is Complex`）。NaN・Infinity を Integer にしようとすると `FloatDomainError` を投げ、`rescue FloatDomainError => e` で受けられます。

## round, floor, ceil, truncate

`Arithmetic.round(Integer|Float|Rational, [Integer], [half: Symbol])`

`Arithmetic.floor(Integer|Float|Rational, [Integer])`

`Arithmetic.ceil(Integer|Float|Rational, [Integer])`

`Arithmetic.truncate(Integer|Float|Rational, [Integer])`

Ruby の `x.round(n)`・`x.floor(n)`・`x.ceil(n)`・`x.truncate(n)` です（結果の型に 1 つ違いがあります）。`round` は最も近い値へ（.5 は既定では 0 から遠い方へ）、`floor` は下へ、`ceil` は上へ、`truncate` は 0 に近い方へ丸めます。

- 桁数 `n` を省くと結果は **Integer** です（引数が Integer でもそのまま Integer）。
- 桁数を付けると結果は **引数と同じ型**: Float には Float、Rational には Rational、Integer には Integer（正の桁数では値はそのまま）。負の桁数は 10 の冪に丸めます。Ruby と違い、0 以下の桁数でもこの規則どおりです: `Arithmetic.round(1234.5, -2)` は `1200.0`（Ruby の `1234.5.round(-2)` は Integer の 1200）、`Arithmetic.round(5r/2, -1)` は `(0/1)`。つまり結果の型は引数の型と桁数の有無だけで決まります。
- `round` は `Float.round` と同じキーワード `half:` を、どの型の引数にも取ります: `:up`（既定。0 から遠い方へ）、`:even`（偶数側へ）、`:down`（0 に近い方へ）。他の Symbol は `ArgumentError`（`invalid rounding mode: foo`）です。`floor`・`ceil`・`truncate` は `half:` を取りません（静的なエラー）。
- NaN・Infinity は桁数なしなら `FloatDomainError`（`rescue` できます）、桁数付きならそのまま返します。

```ruby
p(Arithmetic.round(1.5))           # => 2
p(Arithmetic.round(7r/2))          # => 4
p(Arithmetic.round(3))             # => 3
p(Arithmetic.round(1.2345, 2))     # => 1.23
p(Arithmetic.round(7r/3, 2))       # => (233/100)
p(Arithmetic.round(1234, -2))      # => 1200
p(Arithmetic.round(1234.5, -2))    # => 1200.0
p(Arithmetic.round(5r/2, -1))      # => (0/1)
p(Arithmetic.round(2.5, half: :even))      # => 2
p(Arithmetic.round(5r/2, half: :even))     # => 2
p(Arithmetic.round(25, -1, half: :even))   # => 20
p(Arithmetic.round(1.25, 1, half: :even))  # => 1.2
p(Arithmetic.floor(-1.5))          # => -2
p(Arithmetic.floor(1.567, 1))      # => 1.5
p(Arithmetic.floor(1234.5, -2))    # => 1200.0
p(Arithmetic.ceil(7r/2))           # => 4
p(Arithmetic.ceil(1234, -2))       # => 1300
p(Arithmetic.truncate(-7r/2))      # => -3
p(Arithmetic.truncate(1.999, 2))   # => 1.99
p(Arithmetic.round(Float.NAN, 2))  # => NaN
begin
  Arithmetic.round(Float.NAN)
rescue FloatDomainError => e
  p(Exception.message(e))          # => "NaN"
end
```

型が定まらない値にも一つの操作で使えます:

```ruby
def tenth(x)
  Arithmetic.round(x, 1)
end
p(tenth(1.25))                     # => 1.3
p(tenth(3))                        # => 3
p(tenth(1r/3))                     # => (3/10)
```

```ruby error
p(Arithmetic.round("1.5"))         # !> Arithmetic.round: argument 1 must be Integer|Float|Rational, but is String
```

```ruby error
p(Arithmetic.round(2.5, half: :foo))   # !> ArgumentError: Arithmetic.round: invalid rounding mode: foo
```

```ruby error
p(Arithmetic.round(Float.INFINITY))    # !> FloatDomainError: Arithmetic.round: Infinity
```

## abs

`Arithmetic.abs(Integer|Float|Rational)`

絶対値。結果は引数と同じ型です（Ruby の `x.abs`）。

```ruby
p(Arithmetic.abs(-3))              # => 3
p(Arithmetic.abs(-1.5))            # => 1.5
p(Arithmetic.abs(-1r/3))           # => (1/3)
```

```ruby error
p(Arithmetic.abs(Complex(3, 4)))   # !> Arithmetic.abs: argument 1 must be Integer|Float|Rational, but is Complex
```

## to_i, to_f

`Arithmetic.to_i(Integer|Float|Rational)`

`Arithmetic.to_f(Integer|Float|Rational)`

`to_i` は 0 に近い方へ切り捨てた Integer、`to_f` は最も近い Float を返します。`Integer | Float` の値を Float に揃えるときの `to_f` が代表的な使い方です（検査器は `Float.floor(x)` に `Integer | Float` を渡すと、`Arithmetic.floor(x)` を使うよう助言します）。`to_i` の NaN・Infinity は `FloatDomainError` で、`rescue` できます。

```ruby
p(Arithmetic.to_i(1.9))            # => 1
p(Arithmetic.to_i(7r/2))           # => 3
p(Arithmetic.to_i(7))              # => 7
p(Arithmetic.to_f(3))              # => 3.0
p(Arithmetic.to_f(1r/4))           # => 0.25
p(Arithmetic.to_f(1.5))            # => 1.5
```

```ruby error
p(Arithmetic.to_i(Float.NAN))      # !> FloatDomainError: Arithmetic.to_i: NaN
```

## zero?

`Arithmetic.zero?(Integer|Float|Rational)`

`x == 0` のとき true（`0.0` と `-0.0` も true）。

```ruby
p(Arithmetic.zero?(0))             # => true
p(Arithmetic.zero?(0.0))           # => true
p(Arithmetic.zero?(0r))            # => true
p(Arithmetic.zero?(1))             # => false
```

# Math

Math は Ruby の `Math` モジュールにあたる初等関数の集まりです。型ではなく名前空間で、Math の値はありません。どの関数も実数（Integer、Float、Rational）を取り、結果は常に **Float** です（`Math.sqrt(4)` は `2.0`。Complex は渡せません）。`atan2` と `hypot` の 2 引数の関数と `ldexp` の指数だけは Rational を取らず、Integer か Float です。

Ruby の `Math::PI`・`Math::E` は Sake では引数なしの操作 `Math.PI`・`Math.E` です（Sake に値の定数はありません）。`Math::PI` と Ruby の形で書いても同じ操作として読みます。`Math.log(x, base)` は Ruby と同じく底を取れます（Integer か Float）。

定義域の外の引数（`sqrt(-1)`、`log(-1)`、`acos(2)` など）は Ruby と同じく `Math::DomainError` を投げ、`rescue Math::DomainError => e` で受けられます（[例外とエラー](../08-exceptions.md)）。NaN を渡せば NaN が返り、無限大は IEEE の規則に従います（`log(0)` は `-Infinity`、`exp(1000)` は `Infinity`。例外は出ません）。

## PI, E

`Math.PI()`

`Math.E()`

円周率 π と自然対数の底 e（Float）。`Math.PI` または `Math.PI()` と書きます。

```ruby
p(Math.PI)                         # => 3.141592653589793
p(Math.E)                          # => 2.718281828459045
p(Math.cos(Math.PI))               # => -1.0
p(Math.exp(1) == Math.E)           # => true
```

## sqrt, cbrt

`Math.sqrt(Integer|Float|Rational)`

`Math.cbrt(Integer|Float|Rational)`

平方根・立方根（Float）。`sqrt` の負の引数は `Math::DomainError`。`cbrt` は負の数も取れます（`cbrt(-8)` は `-2.0`）。Integer の正確な平方根が欲しいときは `Integer.sqrt(n)` です。

```ruby
p(Math.sqrt(4))                    # => 2.0
p(Math.sqrt(2.0))                  # => 1.4142135623730951
p(Math.sqrt(9r/4))                 # => 1.5
p(Math.cbrt(-8))                   # => -2.0
p(Math.sqrt(Float.INFINITY))       # => Infinity
begin
  Math.sqrt(-1)
rescue Math::DomainError => e
  p(Exception.message(e))          # => "Numerical argument is out of domain - sqrt"
end
```

```ruby error
p(Math.sqrt(-1))                   # !> Math::DomainError: Math.sqrt: Numerical argument is out of domain - sqrt
```

## sin, cos, tan

`Math.sin(Integer|Float|Rational)`

`Math.cos(Integer|Float|Rational)`

`Math.tan(Integer|Float|Rational)`

三角関数。引数はラジアンです。結果は Float で、`sin(π)` のような値は正確な 0 にはならず、丸め誤差を含みます。

```ruby
p(Math.sin(0))                     # => 0.0
p(Math.cos(0))                     # => 1.0
p(Math.sin(Math.PI / 2))           # => 1.0
p(Math.cos(Math.PI / 3))           # => 0.5000000000000001
p(Math.tan(Math.PI / 4))           # => 0.9999999999999999
```

## asin, acos, atan

`Math.asin(Integer|Float|Rational)`

`Math.acos(Integer|Float|Rational)`

`Math.atan(Integer|Float|Rational)`

逆三角関数（ラジアンの Float）。`asin`・`acos` の引数は -1 から 1 の間でなければならず、外れると `Math::DomainError`。`atan` はどの実数も取り、`-π/2` から `π/2` を返します。

```ruby
p(Math.asin(1))                    # => 1.5707963267948966
p(Math.acos(1))                    # => 0.0
p(Math.asin(0.5))                  # => 0.5235987755982989
p(Math.atan(1) * 4 == Math.PI)     # => true
p(Math.atan(Float.INFINITY))       # => 1.5707963267948966
```

```ruby error
p(Math.acos(2))                    # !> Math::DomainError: Math.acos: Numerical argument is out of domain - acos
```

## atan2

`Math.atan2(Integer|Float, Integer|Float)`

`atan2(y, x)`: 点 `(x, y)` の偏角を `-π` から `π` のラジアン（Float）で返します。`atan(y / x)` と違い、象限を区別し、`x` が 0 でも使えます。引数は Integer か Float で、Rational は静的に `type` の問題です。

```ruby
p(Math.atan2(1, 1))                # => 0.7853981633974483
p(Math.atan2(1.0, -1.0))           # => 2.356194490192345
p(Math.atan2(1, 0))                # => 1.5707963267948966
p(Math.atan2(0, -1))               # => 3.141592653589793
p(Math.atan2(-1, -1))              # => -2.356194490192345
```

```ruby error
p(Math.atan2(1r, 1))               # !> Math.atan2: argument 1 must be Integer|Float, but is Rational
```

## hypot

`Math.hypot(Integer|Float, Integer|Float)`

`sqrt(x² + y²)`（Float）。中間の 2 乗で溢れないように計算します。引数は Integer か Float で、Rational は静的に `type` の問題です。

```ruby
p(Math.hypot(3, 4))                # => 5.0
p(Math.hypot(5, 12))               # => 13.0
p(Math.hypot(1.0, 1.0))            # => 1.4142135623730951
```

```ruby error
p(Math.hypot(1r, 1))               # !> Math.hypot: argument 1 must be Integer|Float, but is Rational
```

## sinh, cosh, tanh

`Math.sinh(Integer|Float|Rational)`

`Math.cosh(Integer|Float|Rational)`

`Math.tanh(Integer|Float|Rational)`

双曲線関数（Float）。

```ruby
p(Math.sinh(0))                    # => 0.0
p(Math.cosh(0))                    # => 1.0
p(Math.sinh(1))                    # => 1.1752011936438014
p(Math.cosh(1))                    # => 1.5430806348152437
p(Math.tanh(Float.INFINITY))       # => 1.0
```

## asinh, acosh, atanh

`Math.asinh(Integer|Float|Rational)`

`Math.acosh(Integer|Float|Rational)`

`Math.atanh(Integer|Float|Rational)`

逆双曲線関数（Float）。`acosh` の引数は 1 以上、`atanh` の引数は -1 から 1 の間でなければならず、外れると `Math::DomainError`。`atanh(1)` は `Infinity`、`atanh(-1)` は `-Infinity` です。

```ruby
p(Math.asinh(1))                   # => 0.881373587019543
p(Math.acosh(2))                   # => 1.3169578969248168
p(Math.atanh(0.5))                 # => 0.5493061443340549
p(Math.atanh(1))                   # => Infinity
```

```ruby error
p(Math.acosh(0))                   # !> Math::DomainError: Math.acosh: Numerical argument is out of domain - acosh
```

## exp

`Math.exp(Integer|Float|Rational)`

`e` の x 乗（Float）。大きな引数は `Infinity` になります（例外は出ません）。

```ruby
p(Math.exp(0))                     # => 1.0
p(Math.exp(2))                     # => 7.38905609893065
p(Math.exp(0.5r))                  # => 1.6487212707001282
p(Math.exp(1000))                  # => Infinity
p(Math.exp(-Float.INFINITY))       # => 0.0
```

## log, log2, log10

`Math.log(Integer|Float|Rational, [Integer|Float])`

`Math.log2(Integer|Float|Rational)`

`Math.log10(Integer|Float|Rational)`

自然対数・2 を底とする対数・10 を底とする対数（Float）。`log(0)` は `-Infinity`、負の引数は `Math::DomainError`。`Math.log(x, base)` は Ruby と同じく底 `base` の対数で、`Math.log(8, 2)` は `3.0` です。底は Integer か Float（Rational は静的に `type` の問題）。負の底は `Math::DomainError`、底 0 は Ruby と同じく `-0.0`、底 1 は `NaN` です。大きな Integer も、Float に直せない大きさでも対数を取れます（Ruby と同じ）。

```ruby
p(Math.log(Math.E))                # => 1.0
p(Math.log(1))                     # => 0.0
p(Math.log(0))                     # => -Infinity
p(Math.log2(8))                    # => 3.0
p(Math.log10(0.001))               # => -3.0
p(Math.log(8r))                    # => 2.0794415416798357
p(Math.log(8, 2))                  # => 3.0
p(Math.log(100, 10))               # => 2.0
p(Math.log(8r, 2.0))               # => 3.0
p(Math.log(10 ** 400))             # => 921.0340371976183
p(Math.log(10 ** 400, 10))         # => 400.0
```

```ruby error
p(Math.log(8, 2r))                 # !> Math.log: argument 2 must be Integer|Float, but is Rational
```

```ruby error
p(Math.log(8, -2))                 # !> Math::DomainError: Math.log: Numerical argument is out of domain - log
```

## erf, erfc

`Math.erf(Integer|Float|Rational)`

`Math.erfc(Integer|Float|Rational)`

誤差関数と補誤差関数 `1 - erf(x)`（Float）。

```ruby
p(Math.erf(0))                     # => 0.0
p(Math.erf(1))                     # => 0.8427007929497149
p(Math.erfc(1))                    # => 0.15729920705028513
p(Math.erf(Float.INFINITY))        # => 1.0
```

## gamma, lgamma

`Math.gamma(Integer|Float|Rational)`

`Math.lgamma(Integer|Float|Rational)`

`gamma` はガンマ関数 Γ(x)（Float。正の整数 n では `(n-1)!`）。`gamma(0)` は `Infinity`、負の整数と `-Infinity` は `Math::DomainError`、172 以上は `Infinity`。`lgamma` は Tuple `[log|Γ(x)|, sign]` を返します: 第 1 要素は絶対値の自然対数（Float）、第 2 要素は Γ(x) の符号（Integer の `1` か `-1`）です。`gamma` が溢れる大きな x でも使えます。

```ruby
p(Math.gamma(5))                   # => 24.0
p(Math.gamma(0.5))                 # => 1.772453850905516
p(Math.gamma(0))                   # => Infinity
p(Math.gamma(172))                 # => Infinity
p(Math.lgamma(6))                  # => [4.787491742782046, 1]
p(Math.lgamma(-0.5))               # => [1.2655121234846454, -1]
v, sign = Math.lgamma(-0.5)
p(sign)                            # => -1
```

```ruby error
p(Math.gamma(-1))                  # !> Math::DomainError: Math.gamma: Numerical argument is out of domain - gamma
```

## frexp, ldexp

`Math.frexp(Integer|Float|Rational)`

`Math.ldexp(Integer|Float|Rational, Integer)`

`frexp(x)` は x を仮数と指数に分けた Tuple `[fraction, exponent]`（`[Float, Integer]`）を返します。`fraction` の絶対値は 0.5 以上 1 未満で、`x == fraction * 2 ** exponent`。0 では `[0.0, 0]`。`ldexp(fraction, exponent)` はその逆で、`fraction * 2 ** exponent` を Float で返します。指数は Integer でなければならず、Float は静的に `type` の問題です。

```ruby
p(Math.frexp(8.0))                 # => [0.5, 4]
p(Math.frexp(0.75))                # => [0.75, 0]
p(Math.frexp(10))                  # => [0.625, 4]
p(Math.frexp(0))                   # => [0.0, 0]
f, e = Math.frexp(8.0)
p(Math.ldexp(f, e))                # => 8.0
p(Math.ldexp(1.0, -2))             # => 0.25
p(Math.ldexp(3, 2))                # => 12.0
```

```ruby error
p(Math.ldexp(0.5, 4.0))            # !> Math.ldexp: argument 2 must be Integer, but is Float
```

# String

String は Ruby の String と同じく、エンコーディングを持つ文字の並びです。リテラルは `"abc"`、`'abc'`、`"a#{x}"`（補間は値を `to_s` で表示します。[値と型](../03-values.md)）で、リテラルは UTF-8、評価のたびに新しい String を作ります。String は**可変**です: 名前が `!` で終わる操作と `concat`、`append_as_bytes`、`prepend`、`insert`、`replace`、`clear`、`setbyte`、`bytesplice`、`force_encoding` は主語をその場で変え、それ以外の操作は主語に触れず新しい String を返します。プログラムが変えられない String は Hash のキー、Set の要素、Symbol の名前（`Symbol.name`）、MatchData が持つ String（`MatchData.string`）、プログラムの引数（`ARGV`）で、それらをその場で変えようとすると実行時に `TypeError` です（`cannot change this String in place: it is a Hash key, a Set element, a Symbol's name, or a program argument`）。

操作はすべて型を付けて書きます: `String.upcase(s)` であって `s.upcase` ではありません。String に使える演算子は `+`（String, String）、`*`（String, Integer）、`%`（書式）、`==`、`!=`、`<`、`<=`、`>`、`>=`、`<=>`（String, String）、`=~`、`!~`（String, Regexp）、添字 `s[i]`、`s[i, n]`、`s[range]` です（[演算子と添字](../05-operators.md)）。以下の `String.+(x, y)` などは、その演算子を関数の形で呼ぶものです。`s[i] = v` はありません: String は添字への書き込みができず（静的に `type` の問題）、`String.sub!`、`String.insert`、`String.bytesplice`、`String.replace` で変えます。

多くの操作が「外れ」に **nil** を返します: `index`、`rindex`、`byteindex`、`byterindex`、`match`、`getbyte`、`casecmp`、`unpack1`、`slice!`、`sub!`、`gsub!`、および何も変わらなかったときに nil を返すその場の形（`upcase!`、`strip!`、`chomp!`、`tr!`、...）です。その結果を検査せずに使うことは `--strict` レベル 2 で `nil` の問題になります。添字の形 `s[i]`、`s[i, n]`、`s[range]`、`String.slice`、`String.byteslice` の nil だけは「外れの nil」（`index-nil`）で、レベル 3 でのみ報告されます（[概観](../01-overview.md)）。

Ruby との違い: `sub` と `gsub` には置換文字列かブロックが要ります。`MatchData` は `m[i]` で読みます（`$~`、`$1` はありません）。`scan`、`partition`、`rpartition` は Ruby が Array を返すところで Tuple を返します。`count`、`start_with?`、`end_with?`、`include?` は引数を 1 つだけ取ります（`chomp`、`delete`、`squeeze` はそれぞれの `!` 形と同じもの、つまり区切りや複数の集合を取れます）。反復（`each_char` など）にはブロックが要ります。[組み込みの操作](../09-builtins.md)の表に操作の一覧があります。

## String[]

`String[*Any]`

**String の Array** を作ります（String そのものではありません）。`Integer[]` や `Tuple[]` と同じ型付き Array で、要素はすべて String でなければならず、`Array.push` などの書き込みも毎回検査されます。String 以外の要素は静的に `type` の問題、実行時は `TypeError` です。空の String の Array は `String[]` です。

```ruby
names = String["a", "b"]
Array.push(names, "c")
p(names)                     # => ["a", "b", "c"]
p(Array.size(String[]))      # => 0
```

```ruby error
Array.push(String[], 1)      # !> Array.push: an element must be String, but is Integer
```

## length, size

`String.length(x)`

`String.size(x)`

文字の個数（Integer）。バイト数ではありません: `"héllo"` は 5 文字、6 バイト（`bytesize`）です。

```ruby
p(String.length("hello"))    # => 5
p(String.size("héllo"))      # => 5
p(String.size(""))           # => 0
```

## bytesize

`String.bytesize(x)`

その String のエンコーディングでのバイト数（Integer）。

```ruby
p(String.bytesize("héllo"))  # => 6
p(String.bytesize(""))       # => 0
```

## empty?

`String.empty?(x)`

文字が 1 つも無いとき true。

```ruby
p(String.empty?(""))         # => true
p(String.empty?(" "))        # => false
```

## +

`String.+(x, Any)`

`a + b` の関数形。`a` の文字に `b` の文字を続けた新しい String を返します。両辺とも String でなければならず、`"a" + 1` は静的に `type` の問題です（Ruby は `TypeError`）。どちらの被演算子も変わりません。

```ruby
s = "abc"
p(s + "d")                   # => "abcd"
p(String.+("a", "b"))        # => "ab"
p(s)                         # => "abc"
```

```ruby error
p("a" + 1)                   # !> the operands are (String, Integer)
```

## *

`String.*(x, Integer)`

`s * n` の関数形。`s` を `n` 回繰り返した新しい String（0 なら `""`）。負の `n` は演算子でも関数形でも `ArgumentError`（`negative argument`）で、rescue できます。

```ruby
p("ab" * 3)                  # => "ababab"
p(String.*("-", 0))          # => ""
begin
  p("ab" * -1)
rescue ArgumentError => e
  puts(Exception.message(e))     # => negative argument
end
```

```ruby error
p(String.*("ab", -1))        # !> ArgumentError: String.*: negative argument -1
```

## %

`String.%(x, Any)`

`fmt % value` の関数形で、`fmt` を書式とする Ruby の `format` です: `"%d items" % 3`。右辺は値 1 つ（Integer、Float、String、Symbol、nil、true、false）か、複数の指示子に対する値の Tuple（`"%s-%s" % [a, b]`）か、名前付き指示子 `%<name>d`、`%{name}` に対する Record または Symbol キーの Hash（`"%<a>05d" % {a: 42}`、`"%<a>05d" % Hash.of(a: 42)`）です。Array は静的に `type` の問題です。指示子は Ruby のもの（`%d`、`%s`、`%f`、`%x`、`%05d`、`%-4s`、`%.2f`、`%p`、...）。指示子に合わない値（`"%d" % "x"`）や値の不足は `ArgumentError`、Record や Hash に無い名前は `KeyError`（`key<b> not found`）、余った値は無視されます。

```ruby
p("%05d|%-4s|%.2f|%x" % [42, "ab", 3.14159, 255])   # => "00042|ab  |3.14|ff"
p("%d items" % 3)            # => "3 items"
p("%s" % :sym)               # => "sym"
p("%p" % nil)                # => "nil"
p(String.%("%03d", 7))       # => "007"
p("%<a>05d" % {a: 42})       # => "00042"
p("%{a}-%<b>s" % {a: 1, b: "x"})     # => "1-x"
p("%<a>05d" % Hash.of(a: 42))   # => "00042"
```

```ruby error
p("%<b>d" % {a: 42})         # !> KeyError: Arithmetic.%: key<b> not found
```

```ruby error
p("%d %d" % 1)               # !> ArgumentError: Arithmetic.%: too few arguments
```

## ==, !=

`String.==(x, Any)`

`String.!=(x, Any)`

両方が String で同じ文字の並びのとき true（`!=` はその否定）。同一性ではなく内容の比較です。右辺が別の型（Integer、Symbol、nil）なら、演算子でも関数形でもただ等しくないだけです: `String.==("a", 1)` は false、`String.!=("a", 1)` は true で、誤りにはなりません。

```ruby
p("a" == "a")                # => true
p("a" != "b")                # => true
p("1" == 1)                  # => false
p("a" == nil)                # => false
p(String.==("a", nil))       # => false
p(String.==("a", 1))         # => false
p(String.!=("a", 1))         # => true
```

## <, <=, >, >=

`String.<(x, Any)`

`String.<=(x, Any)`

`String.>(x, Any)`

`String.>=(x, Any)`

2 つの String を Ruby と同じくバイト単位で比べます: 大文字が先なので `"B" < "a"`、`"10" < "9"`、接頭辞は長い方より小さい。両辺とも String でなければならず、別の型との比較は静的に `type` の問題です。

```ruby
p("a" < "b")                 # => true
p("B" >= "a")                # => false
p("10" < "9")                # => true
p("ab" < "abc")              # => true
p(String.<=("a", "a"))       # => true
```

```ruby error
p("a" < 1)                   # !> the operands are (String, Integer)
```

## <=>

`String.<=>(x, Any)`

その比較の結果を -1、0、1 で返します。両辺とも String でなければならないので、結果が nil になることはありません（Ruby は String 以外に nil を返します）。

```ruby
p("a" <=> "b")               # => -1
p("a" <=> "a")               # => 0
p(String.<=>("b", "a"))      # => 1
```

## between?

`String.between?(x, String, String)`

`<` の順で `lo <= x <= hi` のとき true。

```ruby
p(String.between?("b", "a", "c"))   # => true
p(String.between?("z", "a", "c"))   # => false
```

## clamp

`String.clamp(x, String, String)`

`x` が `lo` と `hi` の間にあればそのまま、外れていれば近い方の端を返します。`lo > hi` は `ArgumentError` です。

```ruby
p(String.clamp("b", "a", "c"))      # => "b"
p(String.clamp("z", "a", "c"))      # => "c"
```

```ruby error
p(String.clamp("b", "c", "a"))      # !> ArgumentError: String.clamp: min argument must be less than or equal to max argument
```

## casecmp

`String.casecmp(x, String)`

ASCII 文字の大小を無視して 2 つの String を比べ、-1、0、1（Integer）を返します。2 つのエンコーディングが互換でないときは nil で、その結果を検査せずに使うことは `--strict` レベル 2 で `nil` の問題です。

```ruby
p(String.casecmp("a", "A"))         # => 0
p(String.casecmp("a", "B"))         # => -1
p(String.casecmp("a", String.encode("a", "UTF-16LE")))   # => nil
```

```ruby error
p(String.casecmp("a", "b") + 1)     # !> the operands may be nil
```

## casecmp?

`String.casecmp?(x, String)`

Unicode のケースフォールディングの後で 2 つが等しいとき true。結果は Boolean で nil にはなりません: エンコーディングが互換でないとき（Ruby のメソッドが nil を返し、`casecmp` も nil になるところ）は **false** です。

```ruby
p(String.casecmp?("a", "A"))        # => true
p(String.casecmp?("a", "b"))        # => false
p(String.casecmp?("a", String.encode("a", "UTF-16LE")))   # => false
```

## =~

`String.=~(x, Any)`

`s =~ re` の関数形。Regexp `re` が `s` に最初に一致する位置（Integer）、一致しなければ nil。右辺は Regexp でなければならず、String は静的に `type` の問題です。nil を検査せずに使うことは `--strict` レベル 2 で `nil` の問題です。`$~` は無いので、グループを読むには `String.match` を使います。

```ruby
p("hello" =~ /l+/)           # => 2
p("hello" =~ /z/)            # => nil
p(String.=~("ab", /b/))      # => 1
```

```ruby error
p(("abc" =~ /b/) + 1)        # !> the operands may be nil
```

## !~

`String.!~(x, Any)`

`s !~ re` の関数形。Regexp が一致しないとき true。

```ruby
p("hello" !~ /z/)            # => true
p(String.!~("ab", /b/))      # => false
```

## []

`String.[](x, Any, [Integer])`

`s[i]`、`s[i, n]`、`s[range]` の関数形。`s[i]` は位置 `i`（Integer。負の値は末尾から）の 1 文字の String、範囲外なら nil。`s[i, n]` は `i` から最大 `n` 文字の部分文字列で、`i` が末尾を越えるか `n` が負なら nil、`i` が長さに等しければ `""`。`s[range]` は Range の範囲の文字で、始点が末尾を越えていれば nil。Ruby と同じく String と Regexp も添字にでき、`s["b"]` はその最初の出現（新しい String）か nil、`s[/re/]` は最初の一致、`s[/re/, 1]` はそのグループです（`String.slice` と同じ。2026-10-11 から）。Float などの添字は静的に `type` の問題で、Range と個数の組は `TypeError` です。結果の型は `String | nil` で、この nil は「外れの nil」（`index-nil`）なので `--strict` レベル 3 でのみ報告されます。

```ruby
s = "hello"
p(s[1])                      # => "e"
p(s[-1])                     # => "o"
p(s[10])                     # => nil
p(s[1, 3])                   # => "ell"
p(s[5, 1])                   # => ""
p(s[6, 1])                   # => nil
p(s[1..2])                   # => "el"
p(s[2..])                    # => "llo"
p(String.[](s, 0))           # => "h"
```

```ruby
s = "hello world"
p(s["wor"])                  # => "wor"
p(s["xyz"])                  # => nil
p(s[/o w/])                  # => "o w"
p(s[/(\w+) (\w+)/, 2])        # => "world"
```

```ruby error
p("abc"[1.5])                # !> the index must be Integer, but is Float
```

## slice

`String.slice(x, Integer|Range|String|Regexp, [Integer])`

`s[i]`、`s[i, n]`、`s[range]` を操作として書いたもの。結果も nil（`index-nil`、レベル 3）も同じです。Ruby の `slice` と同じく、`slice!` が取るものも取れます: String はその最初の出現（新しい String）か nil、Regexp は最初の一致、第 2 引数にグループ番号を添えればそのグループの String（グループが一致に関与しなければ nil）です。String や Range の後に個数を添えると `TypeError` です。

```ruby
s = "hello"
p(String.slice(s, 1))        # => "e"
p(String.slice(s, 1, 2))     # => "el"
p(String.slice(s, 1..2))     # => "el"
p(String.slice(s, 9))        # => nil
p(String.slice(s, "ll"))     # => "ll"
p(String.slice(s, "zz"))     # => nil
p(String.slice(s, /l+/))     # => "ll"
p(String.slice(s, /(l)(o)/, 2))      # => "o"
```

```ruby error
p(String.slice("hello", "ll", 1))    # !> TypeError: String.slice: no implicit conversion of String into Integer
```

## slice!

`String.slice!(x, Integer|Range|String|Regexp, [Integer])`

`s[i]`、`s[i, n]`、`s[range]` の部分を主語から**その場で**取り除き、それを返します。String を渡すとその最初の出現を、Regexp なら最初の一致を取り除きます。取り除くものが無いとき（末尾を越えた添字、現れない String や Regexp）は nil で、主語は変わりません。その結果を検査せずに使うことは `--strict` レベル 2 で `nil` の問題です。

```ruby
s = "hello"
p(String.slice!(s, 0))       # => "h"
p(String.slice!(s, /l+/))    # => "ll"
p(String.slice!(s, "zz"))    # => nil
p(s)                         # => "eo"
```

```ruby error
s = "hello"
c = String.slice!(s, 1)
p(String.upcase(c))          # !> argument 1 may be nil
```

## byteslice

`String.byteslice(x, Integer|Range, [Integer])`

バイト位置 `i` のバイト（1 バイトの String）、`i` から `n` バイト、またはバイト位置の Range の範囲のバイト列。主語のエンコーディングのままなので、多バイト文字を切ると不正な String になりえます。`i`（または Range の始点）が末尾を越えるか `n` が負なら nil（`index-nil`、レベル 3）。Ruby と同じです。

```ruby
p(String.byteslice("héllo", 1))      # => "\xC3"
p(String.byteslice("héllo", 1, 2))   # => "é"
p(String.byteslice("héllo", 1..2))   # => "é"
p(String.byteslice("hello", 9..10))  # => nil
p(String.byteslice("héllo", 9))      # => nil
```

## getbyte

`String.getbyte(x, Integer)`

バイト位置 `i`（負の値は末尾から）のバイト（0..255 の Integer）、範囲外なら nil。その結果を検査せずに使うことは `--strict` レベル 2 で `nil` の問題です。

```ruby
s = "héllo"
p(String.getbyte(s, 0))      # => 104
p(String.getbyte(s, 1))      # => 195
p(String.getbyte(s, -1))     # => 111
p(String.getbyte(s, 99))     # => nil
```

```ruby error
p(String.getbyte("a", 5) + 1)        # !> the operands may be nil
```

## setbyte

`String.setbyte(x, Integer, Integer)`

バイト位置 `i` にバイト `b` を**その場で**格納し（Ruby と同じく `b` の下位 8 ビット）、`b` を返します。範囲外の位置は `IndexError` です。

```ruby
s = "abc"
p(String.setbyte(s, 0, 65))  # => 65
p(s)                         # => "Abc"
```

```ruby error
p(String.setbyte("abc", 10, 1))      # !> IndexError: String.setbyte: index 10 out of string
```

## bytesplice

`String.bytesplice(x, Integer, Integer, String)`

バイト位置 `i` から `n` バイトを String `str` で**その場で**置き換え、主語を返します。範囲外の位置は `IndexError`。位置は文字の境界になければなりません。

```ruby
s = "hello"
p(String.bytesplice(s, 0, 2, "J"))   # => "Jllo"
p(s)                                 # => "Jllo"
```

```ruby error
p(String.bytesplice("abc", 10, 1, "x"))   # !> IndexError: String.bytesplice: index 10 out of string
```

## upcase, downcase, capitalize, swapcase

`String.upcase(x)`

`String.downcase(x)`

`String.capitalize(x)`

`String.swapcase(x)`

文字を大文字に、小文字に、先頭だけ大文字で残りを小文字に、各文字の大小を入れ替えた新しい String。大小の対応は Ruby と同じく Unicode のものです（`"straße"` の upcase は `"STRASSE"`）。

```ruby
p(String.upcase("abc"))          # => "ABC"
p(String.downcase("ABC"))        # => "abc"
p(String.capitalize("hELLO"))    # => "Hello"
p(String.swapcase("Ab"))         # => "aB"
p(String.upcase("straße"))       # => "STRASSE"
```

## upcase!, downcase!, capitalize!, swapcase!

`String.upcase!(x)`

`String.downcase!(x)`

`String.capitalize!(x)`

`String.swapcase!(x)`

同じ変換を**その場で**行います。変わったときは主語を、すでにその形だったときは nil を返します。その結果を検査せずに使うことは `--strict` レベル 2 で `nil` の問題です。

```ruby
s = "Hello"
p(String.upcase!(s))         # => "HELLO"
p(s)                         # => "HELLO"
p(String.upcase!(s))         # => nil
p(String.capitalize!("Abc")) # => nil
```

```ruby error
s = "Hello"
r = String.upcase!(s)
p(String.size(r))            # !> argument 1 may be nil
```

## strip, lstrip, rstrip

`String.strip(x)`

`String.lstrip(x)`

`String.rstrip(x)`

先頭と末尾の空白（`strip`）、先頭だけ（`lstrip`）、末尾だけ（`rstrip`）を除いた新しい String。空白は Ruby と同じく、空白文字、タブ、改行、NUL です。

```ruby
p(String.strip("  a  "))     # => "a"
p(String.lstrip("  a  "))    # => "a  "
p(String.rstrip("  a  "))    # => "  a"
```

## strip!, lstrip!, rstrip!

`String.strip!(x)`

`String.lstrip!(x)`

`String.rstrip!(x)`

同じことを**その場で**行います。何か取り除いたときは主語、取り除くものが無かったときは nil（検査せずに使うと `--strict` レベル 2 で `nil` の問題）。

```ruby
s = "  a  "
p(String.strip!(s))          # => "a"
p(String.strip!(s))          # => nil
p(String.lstrip!("a"))       # => nil
```

## chomp

`String.chomp(x, [String])`

末尾の行末 1 つ（`"\n"`、`"\r\n"`、`"\r"`）を除いた新しい String。行末が無ければそのままの複製です。`suffix` を渡すと代わりにその接尾辞を除きます（Ruby と同じく、`""` は末尾の改行をすべて除きます）。

```ruby
p(String.chomp("a\n"))       # => "a"
p(String.chomp("a\r\n"))     # => "a"
p(String.chomp("a"))         # => "a"
p(String.chomp("abc!", "!"))         # => "abc"
p(String.chomp("abc", "x"))          # => "abc"
p(String.chomp("abc\n\n", ""))       # => "abc"
```

## chomp!

`String.chomp!(x, [String])`

末尾の行末 1 つを**その場で**除きます。`suffix` を渡すとその接尾辞を除きます。何か除いたときは主語、除くものが無かったときは nil（検査せずに使うと `--strict` レベル 2 で `nil` の問題）。

```ruby
s = "a\n"
p(String.chomp!(s))          # => "a"
p(String.chomp!(s))          # => nil
p(String.chomp!("abc", "bc"))        # => "a"
p(String.chomp!("abc", "x"))         # => nil
```

```ruby error
p(String.chomp!("abc") + "!")        # !> the operands may be nil
```

## chop

`String.chop(x)`

最後の文字を除いた新しい String（`"\r\n"` は 1 文字と数えます）。`""` は `""` です。

```ruby
p(String.chop("abc"))        # => "ab"
p(String.chop("a\r\n"))      # => "a"
p(String.chop(""))           # => ""
```

## chop!

`String.chop!(x)`

最後の文字を**その場で**除きます。主語を返し、空だったときは nil（検査せずに使うと `--strict` レベル 2 で `nil` の問題）。

```ruby
s = "abc"
p(String.chop!(s))           # => "ab"
p(String.chop!(""))          # => nil
```

## chr

`String.chr(x)`

先頭の文字を String で返します。空の String なら `""`（Ruby の `chr`）。

```ruby
p(String.chr("abc"))         # => "a"
p(String.chr(""))            # => ""
```

## delete_prefix, delete_suffix

`String.delete_prefix(x, String)`

`String.delete_suffix(x, String)`

先頭の `prefix`、末尾の `suffix` を除いた新しい String。それで始まって（終わって）いなければ、そのままの複製です。

```ruby
p(String.delete_prefix("foobar", "foo"))   # => "bar"
p(String.delete_suffix("foobar", "bar"))   # => "foo"
p(String.delete_prefix("foobar", "x"))     # => "foobar"
```

## delete_prefix!, delete_suffix!

`String.delete_prefix!(x, String)`

`String.delete_suffix!(x, String)`

同じことを**その場で**行います。接頭辞（接尾辞）があって除いたときは主語、無かったときは nil（検査せずに使うと `--strict` レベル 2 で `nil` の問題）。

```ruby
s = "foobar"
p(String.delete_prefix!(s, "foo"))   # => "bar"
p(String.delete_prefix!(s, "foo"))   # => nil
p(String.delete_suffix!(s, "ar"))    # => "b"
p(s)                                 # => "b"
```

## include?, start_with?, end_with?

`String.include?(x, String)`

`String.start_with?(x, String)`

`String.end_with?(x, String)`

`t` が現れるとき、`t` で始まるとき、`t` で終わるとき true。どれも String をちょうど 1 つ取ります（Ruby の `start_with?` は複数の引数や Regexp も取ります）。

```ruby
s = "hello world"
p(String.include?(s, "wor"))     # => true
p(String.start_with?(s, "he"))   # => true
p(String.end_with?(s, "x"))      # => false
```

## index

`String.index(x, String|Regexp, [Integer])`

String `t` の最初の出現、または Regexp の最初の一致の、位置 `pos`（既定 0。負の値は末尾から）以降での文字位置（Integer）。無ければ nil で、検査せずに使うことは `--strict` レベル 2 で `nil` の問題です。`""` は `pos` で見つかります。

```ruby
s = "hello world"
p(String.index(s, "o"))          # => 4
p(String.index(s, "o", 5))       # => 7
p(String.index(s, /w./))         # => 6
p(String.index(s, "l", -3))      # => 9
p(String.index(s, "z"))          # => nil
```

```ruby error
s = "hello"
i = String.index(s, "o")
p(i + 1)                         # !> the operands may be nil
```

## rindex

`String.rindex(x, String|Regexp, [Integer])`

`pos`（既定: 末尾）以前に始まる、`t` の最後の出現（Regexp なら最後の一致）の位置。無ければ nil（検査せずに使うと `--strict` レベル 2 で `nil` の問題）。

```ruby
s = "hello world"
p(String.rindex(s, "o"))         # => 7
p(String.rindex(s, "o", 5))      # => 4
p(String.rindex(s, "z"))         # => nil
```

```ruby error
p(String.rindex("abc", "b") + 1) # !> the operands may be nil
```

## byteindex

`String.byteindex(x, String|Regexp, [Integer])`

`index` と同じですが、結果と `pos` は**バイト**位置です。出現が無ければ nil（検査せずに使うと `--strict` レベル 2 で `nil` の問題）。`pos` は文字の境界になければならず、多バイト文字の途中の位置は `IndexError`（`offset 2 does not land on character boundary`）で、rescue できます。

```ruby
p(String.index("héllo", "l"))        # => 2
p(String.byteindex("héllo", "l"))    # => 3
p(String.byteindex("héllo", "z"))    # => nil
p(String.byteindex("héllo", "l", 3)) # => 3
```

```ruby error
p(String.byteindex("héllo", "l", 2))   # !> IndexError: String.byteindex: offset 2 does not land on character boundary
```

## byterindex

`String.byterindex(x, String|Regexp, [Integer])`

`rindex` のバイト位置版: バイト位置 `pos` 以前に始まる最後の出現。無ければ nil（検査せずに使うと `--strict` レベル 2 で `nil` の問題）。

```ruby
p(String.byterindex("héllo", "l"))      # => 4
p(String.byterindex("héllo", "l", 3))   # => 3
```

```ruby error
p(String.byterindex("abc", "b") + 1)    # !> the operands may be nil
```

## match

`String.match(x, String|Regexp, [Integer])`

位置 `pos`（既定 0）以降で Regexp が最初に一致したところの `MatchData`。一致しなければ nil で、結果を検査せずに使うこと（`if m` 無しの `m[1]`）は `--strict` レベル 2 で `nil` の問題です。String のパターンは Ruby と同じく Regexp として解釈されます（`"."` は任意の 1 文字。`"+"` のような不正なパターンは `RegexpError` で、rescue できます）。`$~` や `$1` は無く、グループは MatchData から `m[0]`、`m[1]`、`m["name"]` で読みます。

```ruby
m = String.match("hello world", /(w)(o)/)
if m
  p(m[0])                      # => "wo"
  p(m[2])                      # => "o"
end
p(String.match("hello", "zzz"))      # => nil
```

```ruby error
p(String.match("a+c", "+"))  # !> RegexpError: String.match: target of repeat operator is not specified: /+/
```

```ruby error
m = String.match("abc", /b/)
p(m[0])                      # !> the operands may be nil (MatchData | nil)
```

## match?

`String.match?(x, String|Regexp, [Integer])`

位置 `pos`（既定 0）以降でパターンが一致するとき true。MatchData は作りません。String のパターンは Regexp として解釈され、不正なパターンは `match` と同じく `RegexpError` です。

```ruby
p(String.match?("hello", /l+/))      # => true
p(String.match?("hello", "o", 8))    # => false
p(String.match?("abc", "b."))        # => true
begin
  p(String.match?("a+c", "+"))
rescue RegexpError => e
  puts(Exception.message(e))         # => target of repeat operator is not specified: /+/
end
```

## scan

`String.scan(x, String|Regexp)`

重ならないすべての一致を左から順に Array で返します。グループが無ければ一致した String の Array。グループがあれば、グループごとに 1 つの String を持つ **Tuple** の Array です（Ruby は Array）。一致に関与しなかったグループはその位置が nil で、これは「外れの nil」（`index-nil`、レベル 3）です。

```ruby
p(String.scan("a1b22", /\d+/))       # => ["1", "22"]
p(String.scan("abab", "ab"))         # => ["ab", "ab"]
p(String.scan("a1b22", /(\w)(\d)/))  # => [["a", "1"], ["b", "2"]]
p(String.scan("a1 b", /(\w)(\d)?/))  # => [["a", "1"], ["b", nil]]
```

## count

`String.count(x, String)`

集合 `chars` に属する文字の個数（Integer）。集合は Ruby の `tr` の書き方です: `"lo"` は文字の列挙、`"a-z"` は範囲、先頭の `^` は否定。集合は 1 つだけです（Ruby は複数の積を取ります）。`"z-a"` のような逆順の範囲は `ArgumentError`（`invalid range "z-a" in string transliteration`）で、`tr`、`delete`、`squeeze` でも同じです。

```ruby
s = "hello world"
p(String.count(s, "lo"))     # => 5
p(String.count(s, "a-z"))    # => 10
p(String.count(s, "^l"))     # => 8
```

```ruby error
p(String.count("abc", "z-a"))    # !> ArgumentError: String.count: invalid range "z-a" in string transliteration
```

## partition, rpartition

`String.partition(x, String|Regexp)`

`String.rpartition(x, String|Regexp)`

`sep`（String か Regexp）の最初（`partition`）または最後（`rpartition`）の出現で分け、**Tuple** `[前, 区切り, 後]` を返します（Ruby は Array）。`sep` が現れないとき、`partition` は `[s, "", ""]`、`rpartition` は `["", "", s]` です。

```ruby
p(String.partition("a=b=c", "="))    # => ["a", "=", "b=c"]
p(String.rpartition("a=b=c", "="))   # => ["a=b", "=", "c"]
p(String.partition("hello", /l+/))   # => ["he", "ll", "o"]
p(String.partition("abc", "x"))      # => ["abc", "", ""]
p(String.rpartition("abc", "x"))     # => ["", "", "abc"]
```

## sub, gsub

`String.sub(x, String|Regexp, [String|Hash]) [{ }]`

`String.gsub(x, String|Regexp, [String|Hash]) [{ }]`

`pattern` の最初の一致（`sub`）またはすべての一致（`gsub`）を置き換えた新しい String。String のパターンは文字どおりに一致します（`"."` はピリオドで、任意の文字ではありません）。置換は 3 つの形のどれかです: **String**（`\0` が一致全体、`\1` が最初のグループ、`\k<name>` が名前付きグループ）、**Hash**（キーが一致した String、値を `to_s` で表示したものが置換。キーに無い一致は取り除かれる）、**ブロック**（一致した String を受け取り（MatchData ではありません）、その結果を `to_s` で表示したものが置換）。置換もブロックも無いと実行時に `ArgumentError` です（Ruby の Enumerator を返す形はありません）。

```ruby
s = "hello"
p(String.sub(s, "l", "L"))                 # => "heLlo"
p(String.gsub(s, "l", "L"))                # => "heLLo"
p(String.gsub(s, /l+/, "<\\0>"))           # => "he<ll>o"
p(String.gsub(s, /(l)(o)/, "\\2\\1"))      # => "helol"
p(String.gsub(s, /[el]/, Hash.of("e" => "3", "l" => 1)))   # => "h311o"
p(String.gsub(s, /l/) { |m| String.upcase(m) })         # => "heLLo"
p(String.sub(s, /l/) { |m| 7 })            # => "he7lo"
p(s)                                       # => "hello"
```

```ruby error
p(String.sub("abc", "b"))    # !> ArgumentError: String.sub: sub needs a replacement or a block
```

## sub!, gsub!

`String.sub!(x, String|Regexp, [String|Hash]) [{ }]`

`String.gsub!(x, String|Regexp, [String|Hash]) [{ }]`

同じ置換を**その場で**行います。何か置き換えたときは主語、パターンが一致しなかったときは nil（主語は変わりません）を返し、結果を検査せずに使うことは `--strict` レベル 2 で `nil` の問題です。置換の形は `sub`、`gsub` と同じです。

```ruby
s = "hello"
p(String.sub!(s, "l", "L"))      # => "heLlo"
p(s)                             # => "heLlo"
p(String.gsub!(s, "zz", "y"))    # => nil
String.gsub!(s, /l/i) { |m| "_" }
p(s)                             # => "he__o"
```

```ruby error
s = "hello"
p(String.sub!(s, "x", "y") + "!")    # !> the operands may be nil
```

## tr

`String.tr(x, String, String)`

集合 `from` の各文字を、`to` の同じ位置の文字で置き換えた新しい String（Ruby の `tr`）。`"a-y"` は範囲、`from` の先頭の `^` は否定、`from` より短い `to` は最後の文字を繰り返し、空の `to` は削除です。逆順の範囲は `ArgumentError`（`invalid range "z-a" in string transliteration`）です。

```ruby
p(String.tr("hello", "el", "ip"))    # => "hippo"
p(String.tr("hello", "a-y", "b-z"))  # => "ifmmp"
p(String.tr("hello", "^l", "*"))     # => "**ll*"
p(String.tr("hello", "lo", ""))      # => "he"
```

```ruby error
p(String.tr("abc", "z-a", "x"))      # !> ArgumentError: String.tr: invalid range "z-a" in string transliteration
```

## tr!

`String.tr!(x, String, String)`

`tr` を**その場で**行います。何か変わったときは主語、変わらなければ nil（検査せずに使うと `--strict` レベル 2 で `nil` の問題）。

```ruby
s = "hello"
p(String.tr!(s, "l", "L"))   # => "heLLo"
p(String.tr!(s, "z", "Z"))   # => nil
```

## tr_s

`String.tr_s(x, String, String)`

`tr` と同じ置き換えをしてから、置き換えた文字の連続を 1 つに縮めます（Ruby の `tr_s`）。

```ruby
p(String.tr_s("hello", "l", "r"))      # => "hero"
p(String.tr_s("aabbcc", "a-c", "x"))   # => "x"
```

## tr_s!

`String.tr_s!(x, String, String)`

`tr_s` を**その場で**行います。何か変わったときは主語、変わらなければ nil（検査せずに使うと `--strict` レベル 2 で `nil` の問題）。

```ruby
s = "aabb"
p(String.tr_s!(s, "a", "x"))     # => "xbb"
p(String.tr_s!(s, "z", "x"))     # => nil
```

## delete

`String.delete(x, String, *String)`

渡したすべての集合（`tr` の書き方: `"a-k"`、`"^l"`）に属する文字を除いた新しい String。複数の集合は Ruby と同じく積です: `delete("hello", "l", "o")` は両方の集合に属する文字が無いので何も除きません。逆順の範囲は `ArgumentError` です。

```ruby
p(String.delete("hello", "l"))     # => "heo"
p(String.delete("hello", "a-k"))   # => "llo"
p(String.delete("hello", "^l"))    # => "ll"
p(String.delete("hello", "l", "o"))        # => "hello"
p(String.delete("hello", "a-z", "^l"))     # => "ll"
```

## delete!

`String.delete!(x, String, *String)`

渡したすべての集合に属する文字を**その場で**削除します（複数の集合は Ruby と同じく積）。何か削除したときは主語、しなかったときは nil（検査せずに使うと `--strict` レベル 2 で `nil` の問題）。

```ruby
s = "hello"
p(String.delete!(s, "l"))              # => "heo"
p(String.delete!(s, "z"))              # => nil
p(String.delete!("hello", "l", "^l"))  # => nil
```

```ruby error
p(String.delete!("a", "z-a"))          # !> ArgumentError: String.delete!: invalid range "z-a"
```

## squeeze

`String.squeeze(x, *String)`

同じ文字の連続を 1 つに縮めた新しい String。集合を渡すと、そのすべてに属する文字の連続だけを縮めます（複数の集合は Ruby と同じく積）。

```ruby
p(String.squeeze("aaabbb  c"))         # => "ab c"
p(String.squeeze("aaabbb  c", "a"))    # => "abbb  c"
p(String.squeeze("aaabbb  c", "a-b"))  # => "ab  c"
p(String.squeeze("aaabbb  c", "a-b", "b"))     # => "aaab  c"
```

## squeeze!

`String.squeeze!(x, *String)`

`squeeze` を**その場で**行います。集合はいくつでも渡せます（Ruby と同じく積）。何か変わったときは主語、変わらなければ nil（検査せずに使うと `--strict` レベル 2 で `nil` の問題）。

```ruby
s = "aaabbb"
p(String.squeeze!(s))                # => "ab"
p(String.squeeze!(s))                # => nil
p(String.squeeze!("aabb", "a"))      # => "abb"
```

## split

`String.split(x, [String|Regexp], [Integer])`

String の Array に分けます。`sep` 無しか `" "` なら空白の連続で分け、先頭の空白は無視します（awk 流）。他の String ならその各出現で、`""` なら 1 文字ずつ、Regexp なら各一致で分け、Regexp のグループは結果に含まれます（Ruby の規則）。`limit`（既定 0）は個数の上限です: 正なら最大その個数で最後の要素に残りが入り、0 なら末尾の空文字列を落とし、負なら残します。ブロックの形はありません。

```ruby
p(String.split("a b  c"))              # => ["a", "b", "c"]
p(String.split("a,b,,c", ","))         # => ["a", "b", "", "c"]
p(String.split("a,b,,c", ",", 2))      # => ["a", "b,,c"]
p(String.split("a,b,,", ","))          # => ["a", "b"]
p(String.split("a,b,,", ",", -1))      # => ["a", "b", "", ""]
p(String.split("a1b2c", /\d/))         # => ["a", "b", "c"]
p(String.split("a1b", /(\d)/))         # => ["a", "1", "b"]
p(String.split("abc", ""))             # => ["a", "b", "c"]
p(String.split("", ","))               # => []
```

## chars

`String.chars(x)`

文字の Array。各要素は 1 文字の String です。

```ruby
p(String.chars("aé"))        # => ["a", "é"]
p(String.chars(""))          # => []
```

## lines

`String.lines(x)`

行の Array。各行は `"\n"` を保ちます（最後の行には無いことがあります）。

```ruby
p(String.lines("a\nb\n"))    # => ["a\n", "b\n"]
p(String.lines("a\nb"))      # => ["a\n", "b"]
p(String.lines(""))          # => []
```

## bytes

`String.bytes(x)`

バイトの Array（0..255 の Integer）。

```ruby
p(String.bytes("aé"))        # => [97, 195, 169]
```

## codepoints

`String.codepoints(x)`

Unicode のコードポイントの Array（Integer）。

```ruby
p(String.codepoints("aé"))   # => [97, 233]
```

## grapheme_clusters

`String.grapheme_clusters(x)`

グラフェムクラスタ（読む人が 1 文字と見るもの: 基底文字と結合文字の組）の Array。各要素は String です。

```ruby
s = "éa"
p(String.length(s))                  # => 3
p(Array.size(String.grapheme_clusters(s)))                       # => 2
p(Array.map(String.grapheme_clusters(s)) { |g| String.length(g) })   # => [2, 1]
```

## each_char

`String.each_char(x) { }`

各文字（1 文字の String）を順にブロックに渡し、主語を返します。ブロックは必須で、無いと静的な誤りです（Ruby の Enumerator を返す形はありません）。

```ruby
r = String.each_char("ab") { |c| p(c) }
# => "a"
# => "b"
p(r)                         # => "ab"
```

```ruby error
String.each_char("ab")       # !> String.each_char requires a block
```

## each_line

`String.each_line(x) { }`

各行を `"\n"` を保ったままブロックに渡し、主語を返します。ブロックは必須です。区切りの引数はありません（Ruby の `each_line(sep)`）。

```ruby
String.each_line("a\nb") { |l| p(l) }
# => "a\n"
# => "b"
```

## each_byte

`String.each_byte(x) { }`

各バイト（Integer）をブロックに渡し、主語を返します。ブロックは必須です。

```ruby
String.each_byte("aé") { |b| p(b) }
# => 97
# => 195
# => 169
```

## each_codepoint

`String.each_codepoint(x) { }`

各コードポイント（Integer）をブロックに渡し、主語を返します。ブロックは必須です。

```ruby
String.each_codepoint("aé") { |c| p(c) }
# => 97
# => 233
```

## each_grapheme_cluster

`String.each_grapheme_cluster(x) { }`

各グラフェムクラスタ（String）をブロックに渡し、主語を返します。ブロックは必須です。

```ruby
String.each_grapheme_cluster("éa") { |g| p(String.length(g)) }
# => 2
# => 1
```

## upto

`String.upto(x, String) { }`

`x`、その `String.succ`、…と `last` まで（`last` を含む）をブロックに渡します。Ruby の `upto`（`"a".upto("e")`）と同じ規則で、値が `last` より長くなったところで止まるので、`x` がすでに `last` を越えていれば何も渡しません。数字だけの String は数として進みます（`"9"` から `"11"`）。主語を返します。

```ruby
String.upto("a", "c") { |s| p(s) }
# => "a"
# => "b"
# => "c"
String.upto("az", "bb") { |s| p(s) }
# => "az"
# => "ba"
# => "bb"
String.upto("9", "11") { |s| p(s) }
# => "9"
# => "10"
# => "11"
String.upto("b", "a") { |s| p(s) }
```

## succ, next

`String.succ(x)`

`String.next(x)`

Ruby の意味で `x` の「次」の新しい String: 右端の英字または数字を 1 つ進め、桁あふれは左へ繰り上げます（`"az"` は `"ba"`、`"a9"` は `"b0"`、`"Zz"` は `"AAa"`）。`""` は `""` です。

```ruby
p(String.succ("az"))         # => "ba"
p(String.next("Zz"))         # => "AAa"
p(String.succ("a9"))         # => "b0"
p(String.succ(""))           # => ""
```

## succ!, next!

`String.succ!(x)`

`String.next!(x)`

主語を**その場で**その「次」に置き換え、主語を返します（nil にはなりません）。

```ruby
s = "az"
p(String.succ!(s))           # => "ba"
p(String.next!(s))           # => "bb"
p(s)                         # => "bb"
```

## reverse

`String.reverse(x)`

文字の順を逆にした新しい String。

```ruby
p(String.reverse("abc"))     # => "cba"
```

## reverse!

`String.reverse!(x)`

主語を**その場で**逆順にし、主語を返します（nil にはなりません）。

```ruby
s = "abc"
p(String.reverse!(s))        # => "cba"
p(s)                         # => "cba"
```

## ljust, rjust, center

`String.ljust(x, Integer, [String])`

`String.rjust(x, Integer, [String])`

`String.center(x, Integer, [String])`

`width` 文字の新しい String: 主語の右（`ljust`）、左（`rjust`）、両側（`center`。余りは右）に `pad`（既定 `" "`）の繰り返しを、幅に合わせて切って詰めます。`width` が長さ以下なら、そのままの複製です。空の `pad` は `ArgumentError`（`zero width padding`）です。

```ruby
p(String.ljust("ab", 5))         # => "ab   "
p(String.rjust("ab", 5, "0"))    # => "000ab"
p(String.center("ab", 6, "*"))   # => "**ab**"
p(String.ljust("ab", 5, "xy"))   # => "abxyx"
p(String.center("ab", 1))        # => "ab"
```

```ruby error
p(String.ljust("a", 3, ""))      # !> ArgumentError: String.ljust: zero width padding
```

## to_s

`String.to_s(x)`

その String 自身。どの型にも `T.to_s(x)` と書けるようにあります。

```ruby
p(String.to_s("x"))          # => "x"
```

## to_i

`String.to_i(x, [Integer])`

String の先頭に書かれた Integer を基数 `base`（2..36、既定 10）で読みます。Ruby の `to_i` と同じく、先頭の空白、符号、数字の間の下線を許し、それ以外の文字で読むのをやめ、数字が無ければ 0 です（誤りにはなりません。[組み込みの操作](../09-builtins.md)の `Integer(s)` は代わりに例外を投げます）。基数 0 は接頭辞を読みます: `0x`（16）、`0b`（2）、`0o` または先頭の `0`（8）。基数 16 では `0x` の接頭辞を許します。2..36 の外の基数（0 以外）は `ArgumentError` です。

```ruby
p(String.to_i("42"))         # => 42
p(String.to_i("  -12abc"))   # => -12
p(String.to_i("abc"))        # => 0
p(String.to_i("ff", 16))     # => 255
p(String.to_i("0x1f", 16))   # => 31
p(String.to_i("0b101", 0))   # => 5
p(String.to_i("012", 0))     # => 10
p(String.to_i("z", 36))      # => 35
```

```ruby error
p(String.to_i("1", 37))      # !> ArgumentError: String.to_i: invalid radix 37
```

## to_f

`String.to_f(x)`

String の先頭に書かれた Float（`"3.5e2"`。下線を許します）。無ければ 0.0 です（誤りにはなりません。`Float(s)` は例外を投げます）。Float に収まらない値は `Infinity` です。

```ruby
p(String.to_f("3.5e2"))      # => 350.0
p(String.to_f("1_000.5"))    # => 1000.5
p(String.to_f("abc"))        # => 0.0
```

## to_r

`String.to_r(x)`

String の先頭に書かれた Rational: `"3/4"`、`"0.75"`、`"1e2"`。数が無ければ `(0/1)` です。

```ruby
p(String.to_r("3/4"))        # => (3/4)
p(String.to_r("0.75"))       # => (3/4)
p(String.to_r("abc"))        # => (0/1)
```

## to_c

`String.to_c(x)`

String の先頭に書かれた Complex（`"1+2i"`）。無ければ `(0+0i)` です。

```ruby
p(String.to_c("1+2i"))       # => (1+2i)
p(String.to_c("x"))          # => (0+0i)
```

## to_sym, intern

`String.to_sym(x)`

`String.intern(x)`

その名前の Symbol。どんな String も Symbol になれ、識別子でないものは引用符付きで表示されます。

```ruby
p(String.to_sym("abc"))      # => :abc
p(String.intern("a b"))      # => :"a b"
```

## hex

`String.hex(x)`

String を 16 進の Integer として読みます（Ruby の `hex`）。符号と `0x` の接頭辞を許し、16 進数字でない文字で読むのをやめ、数字が無ければ 0 です。

```ruby
p(String.hex("ff"))          # => 255
p(String.hex("0x1F"))        # => 31
p(String.hex("-a"))          # => -10
p(String.hex("zz"))          # => 0
```

## oct

`String.oct(x)`

String を 8 進の Integer として読みます（Ruby の `oct`）。接頭辞 `0x`、`0b`、`0o` があれば Ruby と同じく基数が変わります。数字が無ければ 0 です。

```ruby
p(String.oct("17"))          # => 15
p(String.oct("0x1f"))        # => 31
p(String.oct("0b11"))        # => 3
p(String.oct("9"))           # => 0
```

## ord

`String.ord(x)`

先頭の文字のコードポイント（Integer）。空の String は `ArgumentError` です。

```ruby
p(String.ord("a"))           # => 97
p(String.ord("é"))           # => 233
```

```ruby error
p(String.ord(""))            # !> ArgumentError: String.ord: empty string
```

## sum

`String.sum(x, [Integer])`

バイトの和を 2 の `bits` 乗（既定 16）で割った余り。Ruby の簡単なチェックサムです。

```ruby
p(String.sum("abc"))         # => 294
p(String.sum("abc", 8))      # => 38
```

## crypt

`String.crypt(x, String)`

システムの `crypt(3)` による、`salt` を使った String の一方向ハッシュ（Ruby と同じ）。2 バイトより短い salt は `ArgumentError` です。結果はプラットフォームの libc に依存します。

```ruby
p(String.size(String.crypt("abc", "ab")) > 2)   # => true
```

```ruby error
p(String.crypt("abc", "a"))  # !> ArgumentError: String.crypt: salt too short (need >=2 bytes)
```

## concat

`String.concat(x, *String|Integer)`

各引数を主語の末尾に**その場で**追加し、主語を返します。Integer はそのコードポイントの文字として追加されます。

```ruby
s = "a"
p(String.concat(s, "b", 99, "d"))    # => "abcd"
p(s)                                 # => "abcd"
```

## append_as_bytes

`String.append_as_bytes(x, *String|Integer)`

各 String 引数の**バイト列**を、Integer は 1 バイト（下位 8 ビット）として、エンコーディングの変換も妥当性の検査も無しに**その場で**追加します（Ruby と同じ）。結果は不正な String になりえます。主語を返します。

```ruby
s = "a"
p(String.append_as_bytes(s, "é", 255))   # => "aé\xFF"
p(String.bytesize(s))                    # => 4
p(String.valid_encoding?(s))             # => false
```

## prepend

`String.prepend(x, *String)`

引数を順に主語の先頭に**その場で**挿入し、主語を返します。

```ruby
s = "c"
p(String.prepend(s, "a", "b"))   # => "abc"
p(s)                             # => "abc"
```

## insert

`String.insert(x, Integer, String)`

位置 `i` の文字の前に `str` を**その場で**挿入します。負の `i` は末尾から数えた文字の後に挿入するので、-1 は末尾への追加です。主語を返します。範囲外の位置は `IndexError` です。

```ruby
s = "ac"
p(String.insert(s, 1, "b"))      # => "abc"
p(String.insert(s, -1, "d"))     # => "abcd"
p(String.insert(s, 0, "_"))      # => "_abcd"
```

```ruby error
p(String.insert("abc", 10, "x")) # !> IndexError: String.insert: index 10 out of string
```

## replace

`String.replace(x, String)`

主語の内容を `str` の内容で**その場で**置き換え、主語を返します。主語を持つすべての変数から新しい内容が見えます。

```ruby
s = "old"
t = s
String.replace(s, "new")
p(t)                         # => "new"
```

## clear

`String.clear(x)`

すべての文字を**その場で**取り除き、主語（`""` になっています）を返します。

```ruby
s = "hello"
p(String.clear(s))           # => ""
p(String.empty?(s))          # => true
```

## encoding

`String.encoding(x)`

その String のエンコーディングの名前を String で返します（`"UTF-8"`、`"ASCII-8BIT"`、...）。Ruby は Encoding オブジェクトを返しますが、Sake にその型はありません。

```ruby
p(String.encoding("é"))              # => "UTF-8"
p(String.encoding(String.b("é")))    # => "ASCII-8BIT"
```

## force_encoding

`String.force_encoding(x, String)`

主語のバイト列にエンコーディング `enc` のラベルを**その場で**付け替え、主語を返します（Ruby の `force_encoding` と同じ）。バイト列は変換されず、新しいエンコーディングで妥当かは `valid_encoding?` で分かります。未知のエンコーディング名は `ArgumentError`、変えられない String（Hash のキー、Symbol の名前など）は `TypeError` です。

```ruby
s = String.b("\xC3\xA9")
p(String.encoding(s))                # => "ASCII-8BIT"
t = String.force_encoding(s, "UTF-8")
p(String.encoding(s))                # => "UTF-8"
p(Kernel.equal?(s, t))               # => true
p(s)                                 # => "é"
p(String.valid_encoding?(String.force_encoding("\xff", "UTF-8")))   # => false
```

```ruby error
p(String.force_encoding("a", "bogus"))   # !> ArgumentError: String.force_encoding: unknown encoding name - bogus
```

## encode

`String.encode(x, String, [String])`

文字をエンコーディング `to` に変換した新しい String。`from`（既定: 主語のエンコーディング）はバイト列の読み方を指定します。`to` で表せない文字、主語の不正なバイト、未知のエンコーディング名は `EncodingError` です。

```ruby
u = String.encode("é", "UTF-16LE")
p(String.encoding(u))                            # => "UTF-16LE"
p(String.bytesize(u))                            # => 2
p(String.encode("\xE9", "UTF-8", "ISO-8859-1"))  # => "é"
begin
  String.encode("é", "US-ASCII")
rescue EncodingError => e
  p(Exception.message(e))                        # => "U+00E9 from UTF-8 to US-ASCII"
end
```

## valid_encoding?

`String.valid_encoding?(x)`

バイト列がその String のエンコーディングで妥当なとき true。

```ruby
p(String.valid_encoding?("é"))       # => true
p(String.valid_encoding?("\xff"))    # => false
```

## ascii_only?

`String.ascii_only?(x)`

すべての文字が ASCII のとき true（空の String も true）。

```ruby
p(String.ascii_only?("abc"))         # => true
p(String.ascii_only?("é"))           # => false
```

## b

`String.b(x)`

同じバイト列に `ASCII-8BIT`（バイナリ）のラベルを付けた複製。長さはバイト数になります。

```ruby
b = String.b("é")
p(b)                         # => "\xC3\xA9"
p(String.length(b))          # => 2
```

## scrub

`String.scrub(x, [String])`

不正なバイト列をすべて `repl`（既定: 置換文字 `"�"`）で置き換えた新しい String。

```ruby
p(String.scrub("a\xffb", "?"))       # => "a?b"
p(String.valid_encoding?(String.scrub("a\xffb")))   # => true
```

## scrub!

`String.scrub!(x, [String])`

`scrub` を**その場で**行います。置き換えるものが無かったときも主語を返します（他の `!` 形と違い、Ruby と同じく nil にはなりません）。

```ruby
s = "a\xffb"
p(String.scrub!(s, "!"))     # => "a!b"
p(String.scrub!("ok"))       # => "ok"
```

## unicode_normalize

`String.unicode_normalize(x, [Symbol])`

Unicode 正規化形 `form` にした新しい String: `:nfc`（既定）、`:nfd`、`:nfkc`、`:nfkd`。他の Symbol は `ArgumentError`、Unicode でないエンコーディングの String（バイナリの String）は `EncodingError` です。

```ruby
d = String.unicode_normalize("é", :nfd)
p(String.length(d))                          # => 2
p(String.length(String.unicode_normalize(d)))   # => 1
```

```ruby error
p(String.unicode_normalize("a", :bogus))     # !> ArgumentError: String.unicode_normalize: Invalid normalization form bogus
```

## unicode_normalize!

`String.unicode_normalize!(x, [Symbol])`

`unicode_normalize` を**その場で**行い、主語を返します（nil にはなりません）。

```ruby
s = "é"
p(String.unicode_normalize!(s))      # => "é"
p(String.length(s))                  # => 1
```

## unicode_normalized?

`String.unicode_normalized?(x, [Symbol])`

String がすでに形 `form`（既定 `:nfc`）になっているとき true。

```ruby
p(String.unicode_normalized?("é"))           # => true
p(String.unicode_normalized?("é", :nfd))     # => false
```

## dump

`String.dump(x)`

主語を引用符で囲んだ ASCII だけのソース形にした新しい String: 印字できない文字と非 ASCII 文字は `\n` や `é` のようなエスケープになり、`"` と `\` はエスケープされます。`undump` が元に戻します。

```ruby
p(String.dump("a\né"))  # => "\"a\\n\\u00E9\""
```

## undump

`String.undump(x)`

`dump` が主語を作った元の String: 引用符を外し、エスケープを読みます。`dump` の形でない String は Ruby のメッセージを持つ `ArgumentError` です（Ruby のメソッドは RuntimeError を投げますが、Sake の RuntimeError は `raise "msg"` と `Thread.raise` からしか生まれません）。

```ruby
p(String.undump("\"a\\n\""))         # => "a\n"
p(String.undump(String.dump("é")))   # => "é"
begin
  p(String.undump("abc"))
rescue ArgumentError => e
  puts(Exception.message(e))         # => invalid dumped string; not wrapped with '"' nor '"...".force_encoding("...")' form
end
```

```ruby error
p(String.undump("abc"))      # !> ArgumentError: String.undump: invalid dumped string
```

## unpack

`String.unpack(x, String)`

バイト列を `Array.pack` の書式 `fmt` に従って Array に復号します（Ruby の `unpack`）: `C` は符号無しバイト、`v` はリトルエンディアンの 16 ビット Integer、`e` はリトルエンディアンの Float、`a`/`A`/`Z` は String、`*` は繰り返し。要素の型は指示子に従います（Integer、String、Float）。バイトが残っていない指示子は nil を与えます。未知の指示子は `ArgumentError` です。

```ruby
p(String.unpack("AB", "C*"))             # => [65, 66]
p(String.unpack("\x01\x00", "v"))        # => [1]
p(String.unpack("ab", "a1a1"))           # => ["a", "b"]
p(String.unpack("\x00\x00\x80\x3f", "e"))   # => [1.0]
p(String.unpack("", "C"))                # => [nil]
```

```ruby error
p(String.unpack("abc", "Z%"))            # !> ArgumentError: String.unpack: % is not supported
```

## unpack1

`String.unpack1(x, String)`

`unpack(x, fmt)` の最初の要素。そのためのバイトが無ければ nil で、結果を検査せずに使うことは `--strict` レベル 2 で `nil` の問題です。

```ruby
p(String.unpack1("\x01\x00", "v"))   # => 1
p(String.unpack1("abc", "a*"))       # => "abc"
p(String.unpack1("", "C"))           # => nil
```

```ruby error
p(String.unpack1("ab", "C") + 1)     # !> the operands may be nil
```

# Symbol

Symbol は名前そのものを値にしたもので、リテラル `:name` が作ります（空白などを含む名前は `:"hello world"`。[値と型](../03-values.md)）。同じ名前の Symbol は常に同じ 1 つの値で、Hash のキー（`Hash.of(name: 1)` のラベルは Symbol キー）や `case`/`in` の分岐の目印に使います。String から作るには `String.to_sym(s)`（`String.intern`）、String に戻すには `Symbol.to_s`。Ruby の `%i[a b]` はまだ使えず（静的に拒否）、Symbol の Array は `Symbol[:a, :b]` と書きます。

Ruby の `Symbol#to_proc`（`&:name`）はありません。ブロックは値ではないので、`Array.map(xs, &:to_s)` は静的に拒否され、`{ |x| Integer.to_s(x) }` と書きます（[関数とブロック](../04-functions.md)）。

`case s in :a ... in :b ... end` のようにリテラルで分岐するとき、`s` がリテラル以外から来た Symbol（`String.to_sym` の結果など）なら、`--strict=3` は取りこぼす値があることを `exhaustive` として報告します（`else` を足します。[制御構造](../06-control.md)）。

Symbol に使える演算子は `==`、`!=`、`<`、`<=`、`>`、`>=`、`<=>` で、比較は Symbol 同士に限ります（右側が String や Integer だと `<` などは静的に `type` の問題）。`:a == "a"` は false で、関数形 `Symbol.==(:a, "a")` も false です。`Symbol.<(x, y)` などはその演算子の関数形です（[演算子と添字](../05-operators.md)）。

文字列風の操作（`upcase`、`slice`、`match`、`start_with?` など）は、名前を String として処理した結果を返します。Symbol を返すもの（`upcase` など）と String を返すもの（`slice`）があります。どれも Symbol 自体を変えません（Symbol は不変です）。

## Symbol[]

`Symbol[*Any]`

**Symbol の Array** を作ります。`Integer[]` と同じ型付き Array で、要素はすべて Symbol でなければならず、`Array.push` などの書き込みも毎回検査されます。Symbol 以外は静的に `type` の問題、実行時は `TypeError`。空の Symbol の Array は `Symbol[]`。

```ruby
syms = Symbol[:a, :b]
Array.push(syms, :c)
p(syms)                            # => [:a, :b, :c]
p(Array.size(Symbol[]))            # => 0
```

```ruby error
Array.push(Symbol[:a], "x")        # !> Array.push: an element must be Symbol, but is String
```

## to_s, id2name, name

`Symbol.to_s(x)`

`Symbol.id2name(x)`

`Symbol.name(x)`

名前を String で返します。`to_s` と `id2name` は毎回新しい（書き換えられる）String を返し、`name` は Symbol が持つ名前そのものを返すので、Ruby と同じく凍結されていて、`String.upcase!` などで書き換えると `TypeError` です。

```ruby
p(Symbol.to_s(:hello))             # => "hello"
p(Symbol.id2name(:"with space"))   # => "with space"
s = Symbol.to_s(:abc)
String.upcase!(s)
p(s)                               # => "ABC"
p(Symbol.name(:abc))               # => "abc"
```

```ruby error
s = Symbol.name(:abc)
String.upcase!(s)                  # !> TypeError: String.upcase!: cannot change this String in place
```

## to_sym, intern

`Symbol.to_sym(x)`

`Symbol.intern(x)`

その Symbol 自身を返します（Ruby と同じ）。String から Symbol を作るのは `String.to_sym`、`String.intern` です。

```ruby
p(Symbol.to_sym(:a))               # => :a
p(Symbol.intern(:a) == :a)         # => true
p(String.to_sym("a") == :a)        # => true
```

## length, size

`Symbol.length(x)`

`Symbol.size(x)`

名前の文字数（Integer。バイト数ではありません）。

```ruby
p(Symbol.length(:hello))           # => 5
p(Symbol.size(:日本))              # => 2
```

## empty?

`Symbol.empty?(x)`

名前が空（`:""`）なら true。

```ruby
p(Symbol.empty?(:""))              # => true
p(Symbol.empty?(:a))               # => false
```

## encoding

`Symbol.encoding(x)`

名前のエンコーディングの名前を String で返します（Ruby は Encoding オブジェクトを返します）。ASCII だけの名前は `"US-ASCII"`、それ以外は `"UTF-8"`。

```ruby
p(Symbol.encoding(:hello))         # => "US-ASCII"
p(Symbol.encoding(:日本))          # => "UTF-8"
```

## upcase, downcase, capitalize, swapcase

`Symbol.upcase(x)`

`Symbol.downcase(x)`

`Symbol.capitalize(x)`

`Symbol.swapcase(x)`

名前を大文字に・小文字に・先頭だけ大文字（残りは小文字）に・大小反転にした新しい Symbol を返します。Ruby の `String` の同名の操作と同じで、Unicode の文字も変換されます。オプション引数（`:ascii` など）はありません。

```ruby
p(Symbol.upcase(:hello))           # => :HELLO
p(Symbol.downcase(:HeLLo))         # => :hello
p(Symbol.capitalize(:hello_world)) # => :Hello_world
p(Symbol.swapcase(:HeLLo))         # => :hEllO
p(Symbol.downcase(:ÀB))            # => :àb
```

## succ, next

`Symbol.succ(x)`

`Symbol.next(x)`

名前を Ruby の `String#succ` で 1 つ進めた新しい Symbol（`:a` → `:b`、`:az` → `:ba`、`:zz` → `:aaa`、`:a9` → `:b0`）。

```ruby
p(Symbol.succ(:a))                 # => :b
p(Symbol.next(:az))                # => :ba
p(Symbol.succ(:zz))                # => :aaa
p(Symbol.succ(:a9))                # => :b0
```

## start_with?, end_with?

`Symbol.start_with?(x, String)`

`Symbol.end_with?(x, String)`

名前が String `s` で始まる・終わるなら true。引数は String で、Symbol を渡すのは静的に `type` の問題です（Ruby の複数引数や Regexp の形はありません）。

```ruby
p(Symbol.start_with?(:hello, "he"))   # => true
p(Symbol.end_with?(:hello, "lo"))     # => true
p(Symbol.start_with?(:hello, "x"))    # => false
```

```ruby error
p(Symbol.start_with?(:abc, :a))    # !> Symbol.start_with?: argument 2 must be String, but is :a
```

## slice

`Symbol.slice(x, Integer, [Integer])`

名前の一部を String で返します。`slice(s, i)` は位置 `i` の 1 文字（負の値は末尾から）、`slice(s, i, n)` は位置 `i` から `n` 文字。範囲外なら nil（Ruby の `String#slice` と同じで、`i` が長さに等しいときの `slice(s, i, n)` は `""`）。結果は nil になりうるので、そのまま使うと level 2 で報告されます。Range や String を添字にする形はありません（静的に `type` の問題）。

```ruby
p(Symbol.slice(:hello, 1))         # => "e"
p(Symbol.slice(:hello, -1))        # => "o"
p(Symbol.slice(:hello, 1, 3))      # => "ell"
p(Symbol.slice(:hello, 10))        # => nil
p(Symbol.slice(:abc, 3, 1))        # => ""
```

```ruby error
p(Symbol.slice(:abc, 0..1))        # !> Symbol.slice: argument 2 must be Integer, but is Range[Integer]
```

## match

`Symbol.match(x, Regexp|String)`

名前にパターンを当て、最初に一致した MatchData を返します。一致しなければ nil（level 2 で報告）。パターンが String なら正規表現のソースとして扱います（Ruby と同じ）。

```ruby
m = Symbol.match(:hello, /l+/)
p(m)                               # => #<MatchData "ll">
if m
  p(MatchData.to_s(m))             # => "ll"
end
p(Symbol.match(:hello, "l+"))      # => #<MatchData "ll">
p(Symbol.match(:hello, /z/))       # => nil
```

## match?

`Symbol.match?(x, Regexp|String)`

名前がパターンに一致すれば true。MatchData を作らないので、一致したかどうかだけが要るときはこちらを使います。

```ruby
p(Symbol.match?(:hello, /ell/))    # => true
p(Symbol.match?(:hello, "x"))      # => false
```

## casecmp

`Symbol.casecmp(x, Symbol)`

大文字小文字を区別せず（ASCII の範囲で）2 つの Symbol の名前を比べ、-1、0、1 を返します。引数は Symbol でなければなりません（String は静的に `type` の問題）。Ruby の `casecmp` が比べられないときに nil を返すことに合わせて結果の型は `Integer | nil` なので、そのまま計算に使うと level 2 で報告されます。

```ruby
p(Symbol.casecmp(:a, :A))          # => 0
p(Symbol.casecmp(:a, :B))          # => -1
p(Symbol.casecmp(:b, :A))          # => 1
```

```ruby error
p(Symbol.casecmp(:a, "b"))         # !> Symbol.casecmp: argument 2 must be Symbol, but is String
```

## casecmp?

`Symbol.casecmp?(x, Symbol)`

大文字小文字を区別せず（Unicode の case folding で）2 つの Symbol の名前が等しければ true。`casecmp` と違い、結果は Boolean で nil にはなりません: Ruby のメソッドが nil を返すところ（エンコーディングが互換でないとき）は false です。

```ruby
p(Symbol.casecmp?(:a, :A))         # => true
p(Symbol.casecmp?(:a, :b))         # => false
p(Symbol.casecmp?(:Straße, :STRASSE))   # => true
```

## ==, !=

`Symbol.==(x, Any)`

`Symbol.!=(x, Any)`

同じ名前の Symbol なら true（`!=` はその否定）。右側が Symbol でないもの（String、Integer、nil）なら、演算子でも関数形でもただ等しくないだけです: `Symbol.==(:a, "a")` は false で、誤りにはなりません。

```ruby
p(:a == :a)                        # => true
p(:a != :b)                        # => true
p(:a == "a")                       # => false
p(Symbol.==(:a, :a))               # => true
p(Symbol.==(:a, "a"))              # => false
p(Symbol.!=(:a, "a"))              # => true
```

## <, <=, >, >=

`Symbol.<(x, Any)`

`Symbol.<=(x, Any)`

`Symbol.>(x, Any)`

`Symbol.>=(x, Any)`

2 つの Symbol の名前を String として比べます（Ruby と同じ、バイト順）。右側は Symbol でなければならず、String や Integer は静的に `type` の問題です。

```ruby
p(:a < :b)                         # => true
p(:b >= :c)                        # => false
p(Symbol.<=(:a, :a))               # => true
```

```ruby error
p(:a < "a")                        # !> which the left operand's type does not support
```

## <=>

`Symbol.<=>(x, Any)`

名前の比較の結果を -1、0、1 で返します。規則は `<` と同じで、右側は Symbol に限ります。`Array.sort_by` のキーに使えます。

```ruby
p(:a <=> :b)                       # => -1
p(:aa <=> :b)                      # => -1
p(Symbol.<=>(:a, :a))              # => 0
```

# Regexp

Regexp は正規表現です。リテラル `/\d+/` と、Ruby と同じフラグ `i`（大文字小文字を区別しない）、`m`（`.` が改行にも一致）、`x`（空白とコメントを無視）、`n`（バイト列として扱う。`/a/n` のエンコーディングは US-ASCII）が使えます。`/a#{x}/` で String を埋め込めます。文字列から組み立てるには `Regexp.new(s, flags)`。文法は Ruby（Onigmo）のものそのままで、名前付きグループ `(?<name>...)` も使えます（[値と型](../03-values.md)）。

Ruby との大きな違いは、一致の結果がグローバルに残らないことです。`$~`、`$1`、`Regexp.last_match` は存在せず、`/(?<y>\d+)/ =~ s` が局所変数 `y` を作ることもありません（静的なエラー）。一致の結果は `Regexp.match` が返す MatchData を変数に置いて読みます（[MatchData](MatchData.md)）。

Regexp に使える演算子は `=~`（String との一致位置、無ければ nil）、`==`、`!=` です。String 側の `s =~ re`、`s !~ re` もあります。`String.match`、`match?`、`scan`、`sub`、`gsub`、`split`、`index` なども Regexp を取ります（[演算子と添字](../05-operators.md)）。Regexp は Hash のキーや Set の要素にはなれません（`TypeError`）。

## new

`Regexp.new(String, [String])`

ソースの String から Regexp を作ります。第 2 引数はフラグの文字を並べた String（省略時 ""）で、リテラルと同じ `i`、`m`、`x`、`n` が使えます。それ以外の文字は実行時に `ArgumentError`。ソースが正規表現として正しくなければ `RegexpError` で、rescue できます（Ruby の `Regexp.new(s, Regexp::IGNORECASE)` のような Integer のフラグは取りません）。ソースの特殊文字をそのまま一致させたいときは `Regexp.escape` を通します。

```ruby
p(Regexp.new("a.b"))                        # => /a.b/
re = Regexp.new("ab+", "i")
p(re)                                       # => /ab+/i
p(Regexp.match?(re, "ABB"))                 # => true
p(Regexp.options(Regexp.new("a", "mi")))    # => 5
p(Regexp.new("a", "n"))                     # => /a/n
begin
  p(Regexp.new("("))
rescue RegexpError => e
  puts(Exception.message(e))                # => end pattern with unmatched parenthesis: /(/
end
```

```ruby error
p(Regexp.new("a", "q"))        # !> ArgumentError: Regexp.new: unknown regexp option: q
```

```ruby error
p(Regexp.new("("))             # !> RegexpError: Regexp.new: end pattern with unmatched parenthesis: /(/
```

## escape

`Regexp.escape(String)`

String の中の正規表現の特殊文字（`.`、`*`、`(`、空白など）をバックスラッシュで逃がした String。`Regexp.new(Regexp.escape(s))` が、`s` そのものに一致する Regexp です。

```ruby
p(Regexp.escape("a.b*c"))                                 # => "a\\.b\\*c"
word = "a.b"
re = Regexp.new(Regexp.escape(word))
p(Regexp.match?(re, "a.b"))                               # => true
p(Regexp.match?(re, "axb"))                               # => false
```

## source

`Regexp.source(x)`

正規表現のソース（String）。フラグは含みません。埋め込みは展開済みの形です。

```ruby
p(Regexp.source(/\d+/))        # => "\\d+"
p(Regexp.source(/a b/x))       # => "a b"
x = "c"
p(Regexp.source(/a#{x}/i))     # => "ac"
```

## options

`Regexp.options(x)`

フラグをビットで表した Integer（Ruby と同じ: `i` が 1、`x` が 2、`m` が 4、`n` が 32）。

```ruby
p(Regexp.options(/a/))         # => 0
p(Regexp.options(/a/i))        # => 1
p(Regexp.options(/a/imx))      # => 7
p(Regexp.options(/a/n))        # => 32
```

## casefold?

`Regexp.casefold?(x)`

フラグ `i` が付いているとき true。

```ruby
p(Regexp.casefold?(/a/i))      # => true
p(Regexp.casefold?(/a/))       # => false
```

## encoding

`Regexp.encoding(x)`

正規表現のエンコーディングの名前（String）。ASCII だけのソースは "US-ASCII"、非 ASCII 文字を含むと "UTF-8"、`/.../n` は "US-ASCII"（バイト列として一致します）。

```ruby
p(Regexp.encoding(/a/))        # => "US-ASCII"
p(Regexp.encoding(/あ/))       # => "UTF-8"
p(Regexp.encoding(/a/n))       # => "US-ASCII"
```

## fixed_encoding?

`Regexp.fixed_encoding?(x)`

エンコーディングが固定されているとき true（非 ASCII 文字を含むソース）。ASCII だけのソースと `/.../n` は false で、どのエンコーディングの String にも一致を試せます。Ruby と同じです。

```ruby
p(Regexp.fixed_encoding?(/a/))     # => false
p(Regexp.fixed_encoding?(/あ/))    # => true
```

## timeout

`Regexp.timeout(x)`

その Regexp に設定された一致のタイムアウト（秒、Float）か **nil**。Sake ではタイムアウトを設定する手段が無いので常に nil で、`--strict`（レベル 2）は確かめずに使うと報告します。

```ruby
p(Regexp.timeout(/a/))         # => nil
```

## names

`Regexp.names(x)`

名前付きグループの名前の Array（String。現れた順、重複は 1 つ）。名前付きグループが無ければ空の Array。

```ruby
p(Regexp.names(/(?<y>\d+)-(?<m>\d+)/))    # => ["y", "m"]
p(Regexp.names(/(\d+)/))                  # => []
```

## named_captures

`Regexp.named_captures(x)`

名前付きグループの名前（String）から、その番号の Array への Hash。同じ名前を 2 度使うと番号が 2 つ並びます。

```ruby
p(Regexp.named_captures(/(?<y>\d+)-(?<m>\d+)/))   # => {"y" => [1], "m" => [2]}
p(Regexp.named_captures(/(?<a>.)(?<a>.)/))        # => {"a" => [1, 2]}
p(Regexp.named_captures(/(a)/))                   # => {}
```

## match

`Regexp.match(x, String, [Integer])`

String の中で最初に一致した箇所の MatchData。一致しなければ **nil** で、`--strict`（レベル 2）は確かめずに使うと報告します（`if m` や `or raise` で確かめます）。第 3 引数は探し始める位置（文字単位。省略時 0、負なら末尾から）。`String.match(s, re)` も同じです。Ruby と違い `$~` には何も残りません。

```ruby
re = /(?<y>\d+)-(?<m>\d+)/
m = Regexp.match(re, "on 2026-10")
if m
  p(m["y"])                               # => "2026"
end
p(Regexp.match(re, "none"))               # => nil
n = Regexp.match(/\d/, "a1b2", 2) or raise("no digit")
p(n[0])                                   # => "2"
```

```ruby error
m = Regexp.match(/a/, "a")
p(m[0])                                   # !> the operands may be nil (MatchData | nil)
```

## match?

`Regexp.match?(x, String, [Integer])`

一致するところがあれば true。MatchData を作らないので、一致したかだけを知りたいときはこちらが軽いです。第 3 引数は探し始める位置。

```ruby
p(Regexp.match?(/\d+/, "a1"))         # => true
p(Regexp.match?(/\d+/, "abc"))        # => false
p(Regexp.match?(/\d/, "1abc", 1))     # => false
```

## =~

`Regexp.=~(x, Any)`

`re =~ s` の関数形。最初に一致した位置（Integer、文字単位）か、一致しなければ **nil**（`--strict` レベル 2 で報告）。右側は String でなければなりません。`s =~ re` も同じ結果で、`s !~ re` は一致しないとき true。Ruby と違い、名前付きグループが局所変数になることはなく、`$~` も残りません。

```ruby
p(/b/ =~ "abc")                # => 1
p(/z/ =~ "abc")                # => nil
p("abc" =~ /c/)                # => 2
p("abc" !~ /z/)                # => true
p(Regexp.=~(/b/, "abc"))       # => 1
```

```ruby error
if /(?<y>\d+)/ =~ "12"
  p(y)                         # !> named captures do not create local variables in Sake
end
```

## ==, !=

`Regexp.==(x, Any)`

`Regexp.!=(x, Any)`

2 つの Regexp のソースとフラグが同じとき true（`!=` はその否定）。右側が Regexp 以外なら等しくありません。

```ruby
p(/a/ == /a/)                  # => true
p(/a/ == /a/i)                 # => false
p(/a/ != /b/)                  # => true
p(/a/ == "a")                  # => false
```

## union

`Regexp.union(*String|Regexp|Array)`

引数のどれかに一致する Regexp。String は `escape` した上で、Regexp はそのフラグを保ったまま `|` でつなぎます。引数が無ければ何にも一致しない `/(?!)/`。パターンは個々に並べるか、Ruby と同じく String と Regexp の Array を **1 つ**だけ渡します（`Regexp.union(Any["a", "b"])`）。他の引数と並べた Array や、String でも Regexp でもない要素は実行時に `TypeError` です。

```ruby
p(Regexp.union("a.b", /c/i))                              # => /a\.b|(?i-mx:c)/
p(Regexp.match?(Regexp.union("cat", "dog"), "hotdog"))    # => true
p(Regexp.union())                                         # => /(?!)/
p(Regexp.union(Any["a", "b"]))                          # => /a|b/
p(Regexp.union(Any["a.b", /c/]))                        # => /a\.b|(?-mix:c)/
```

```ruby error
p(Regexp.union("a", Any["b"]))    # !> TypeError: Regexp.union: no implicit conversion of Array into String
```

# MatchData

MatchData は正規表現が一致した結果です。`Regexp.match(re, s)` と `String.match(s, re)` が返し、一致しなかったときは nil なので、まず確かめてから使います（[Regexp](Regexp.md)）。Ruby の `$~`、`$1` のようなグローバルは無く、MatchData を変数に置いて添字で読みます（[値と型](../03-values.md)）。

グループは Ruby と同じ番号です: 0 が一致全体、1 から順に `(...)` のグループ。名前付きグループ `(?<name>...)` は名前（String）でも読めます。Ruby と同じく、名前付きグループが 1 つでもあると、名前の無い `(...)` はグループとして数えません。一致に参加しなかったグループ（`(a)?` が空振りしたとき）は nil です。

MatchData に使える演算子は添字 `m[k]` だけで、`m[k] = v` はできません（[演算子と添字](../05-operators.md)）。MatchData 自体は Hash のキーにはなれません。

## []

`MatchData.[](x, Any)`

`m[k]` の関数形。`k` が Integer ならその番号のグループの String（0 は一致全体、負の値は末尾から）、String か Symbol ならその名前のグループの String です。一致に参加しなかったグループと、**範囲外の番号**は nil。一方、**無い名前**は実行時に `IndexError` です。戻り値は `x[k]` の nil（添字外れの nil）なので、`--strict` のレベル 2 では確かめずに使っても報告されず、レベル 3（`index-nil`）で報告されます。Integer と String 以外の添字は `TypeError`。

```ruby
m = Regexp.match(/(?<y>\d+)-(?<m>\d+)?/, "ab 12- cd") or raise("no match")
p(m[0])                       # => "12-"
p(m[1])                       # => "12"
p(m[2])                       # => nil
p(m[9])                       # => nil
p(m["y"])                     # => "12"
p(m[:y])                      # => "12"
p(MatchData.[](m, -1))        # => nil
```

```ruby error
m = Regexp.match(/(?<y>\d+)/, "12") or raise("no match")
p(m["z"])                     # !> IndexError: MatchData.[]: undefined group name reference: z
```

## captures

`MatchData.captures(x)`

グループ 1 以降の String の Array（一致全体は含みません）。参加しなかったグループは nil で、要素の型は String か nil です。

```ruby
m = Regexp.match(/(\d+)-(\d+)?/, "12-") or raise("no match")
p(MatchData.captures(m))      # => ["12", nil]
```

## named_captures

`MatchData.named_captures(x)`

名前付きグループの名前（String）から一致した String（参加しなければ nil）への Hash。名前付きグループが無ければ空の Hash。

```ruby
m = Regexp.match(/(?<y>\d+)-(?<m>\d+)?/, "12-") or raise("no match")
p(MatchData.named_captures(m))    # => {"y" => "12", "m" => nil}
```

## names

`MatchData.names(x)`

名前付きグループの名前の Array（`Regexp.names` と同じ）。

```ruby
m = Regexp.match(/(?<y>\d+)-(?<m>\d+)?/, "12-") or raise("no match")
p(MatchData.names(m))         # => ["y", "m"]
```

## to_a

`MatchData.to_a(x)`

一致全体とすべてのグループの Array（`m[0]`、`m[1]`、...）。参加しなかったグループは nil。

```ruby
m = Regexp.match(/(\d+)-(\d+)?/, "12-") or raise("no match")
p(MatchData.to_a(m))          # => ["12-", "12", nil]
```

## to_s

`MatchData.to_s(x)`

一致全体の String（`m[0]` と同じですが、nil にはなりません）。

```ruby
m = Regexp.match(/\d+/, "ab 12 cd") or raise("no match")
p(MatchData.to_s(m))          # => "12"
```

## values_at

`MatchData.values_at(x, *Integer)`

指定した番号のグループの String を並べた Array（Ruby の `Array.values_at` と同じ要領）。参加しなかったグループと範囲外の番号は nil。番号は Integer だけで、名前は取れません（静的に `type` の問題）。

```ruby
m = Regexp.match(/(\d+)-(\d+)?/, "12-") or raise("no match")
p(MatchData.values_at(m, 0, 2, 9))    # => ["12-", nil, nil]
p(MatchData.values_at(m))             # => []
```

## match

`MatchData.match(x, Integer)`

番号のグループの String（参加しなければ nil。「外れの nil」（`index-nil`）なので `--strict` レベル 3 でのみ報告）。`m[i]` との違いは、範囲外の番号が nil ではなく実行時に `IndexError` になることです。

```ruby
m = Regexp.match(/(\d+)-(\d+)?/, "12-") or raise("no match")
p(MatchData.match(m, 1))      # => "12"
p(MatchData.match(m, 2))      # => nil
```

```ruby error
m = Regexp.match(/(a)/, "a") or raise("no match")
p(MatchData.match(m, 5))      # !> IndexError: MatchData.match: index 5 out of matches
```

## match_length

`MatchData.match_length(x, Integer)`

番号のグループが一致した文字数（Integer）。参加しなければ nil（「外れの nil」、`index-nil`、レベル 3）、範囲外の番号は `IndexError`。

```ruby
m = Regexp.match(/(\d+)-(\d+)?/, "12-") or raise("no match")
p(MatchData.match_length(m, 1))   # => 2
p(MatchData.match_length(m, 2))   # => nil
```

## pre_match, post_match

`MatchData.pre_match(x)`

`MatchData.post_match(x)`

一致した箇所より前の String と後の String（Ruby の `` $` `` と `$'`）。

```ruby
m = Regexp.match(/\d+/, "ab 12 cd") or raise("no match")
p(MatchData.pre_match(m))     # => "ab "
p(MatchData.post_match(m))    # => " cd"
```

## begin, end

`MatchData.begin(x, Integer)`

`MatchData.end(x, Integer)`

番号のグループが一致した始めの位置と終わりの位置（文字単位の Integer。`end` は最後の文字の次）。参加しなかったグループでは **nil** です。結果の型は `Integer | nil` で、この nil は「外れの nil」（`index-nil`）なので `--strict` レベル 3 でのみ報告されます（`bytebegin`、`byteend`、`offset`、`byteoffset`、`match`、`match_length` の nil も同じです）。範囲外の番号は `IndexError`（`index 5 out of matches`）で、rescue できます。

```ruby
m = Regexp.match(/(\d+)-(\d+)?/, "ab 12-") or raise("no match")
p(MatchData.begin(m, 0))      # => 3
p(MatchData.end(m, 0))        # => 6
p(MatchData.begin(m, 1))      # => 3
p(MatchData.end(m, 1))        # => 5
p(MatchData.begin(m, 2))      # => nil
b = MatchData.begin(m, 2)
if b
  p(b)
else
  puts("group 2 did not take part")      # => group 2 did not take part
end
```

```ruby error
m = Regexp.match(/(a)/, "a") or raise("no match")
p(MatchData.begin(m, 5))      # !> IndexError: MatchData.begin: index 5 out of matches
```

## offset

`MatchData.offset(x, Integer)`

番号のグループの `[begin, end]` の Tuple。参加しなかったグループは `[nil, nil]`、範囲外の番号は `IndexError`。

```ruby
m = Regexp.match(/(\d+)-(\d+)?/, "ab 12-") or raise("no match")
p(MatchData.offset(m, 1))     # => [3, 5]
p(MatchData.offset(m, 2))     # => [nil, nil]
```

```ruby error
m = Regexp.match(/(a)/, "a") or raise("no match")
p(MatchData.offset(m, 5))     # !> IndexError: MatchData.offset: index 5 out of matches
```

## bytebegin, byteend

`MatchData.bytebegin(x, Integer)`

`MatchData.byteend(x, Integer)`

`begin`、`end` のバイト単位の版（Integer）。マルチバイト文字を含む String で文字の位置と違ってきます。参加しなかったグループは nil（「外れの nil」、`index-nil`、レベル 3）、範囲外の番号は `IndexError`。

```ruby
m = Regexp.match(/(い)/, "あいう") or raise("no match")
p(MatchData.begin(m, 1))      # => 1
p(MatchData.bytebegin(m, 1))  # => 3
p(MatchData.byteend(m, 1))    # => 6
```

## byteoffset

`MatchData.byteoffset(x, Integer)`

`offset` のバイト単位の版: `[bytebegin, byteend]` の Tuple。参加しなかったグループは `[nil, nil]`。

```ruby
m = Regexp.match(/(い)/, "あいう") or raise("no match")
p(MatchData.byteoffset(m, 1))     # => [3, 6]
p(MatchData.offset(m, 1))         # => [1, 2]
```

## length, size

`MatchData.length(x)`

`MatchData.size(x)`

グループの個数 + 1（一致全体を含む。`to_a` の長さ）。

```ruby
m = Regexp.match(/(\d+)-(\d+)?/, "12-") or raise("no match")
p(MatchData.size(m))          # => 3
p(MatchData.length(m))        # => 3
```

## regexp

`MatchData.regexp(x)`

この一致を作った Regexp。

```ruby
m = Regexp.match(/\d+/i, "12") or raise("no match")
p(MatchData.regexp(m))        # => /\d+/i
```

## string

`MatchData.string(x)`

一致を試した String 全体。凍結されていて、`String.upcase!` のようなその場の変更は `TypeError` です。

```ruby
m = Regexp.match(/\d+/, "ab 12 cd") or raise("no match")
p(MatchData.string(m))        # => "ab 12 cd"
```

# Array

Array は長さが変わる並びです。`Any[1, 2, 3]` が Array を作ります。Ruby の `[1, 2, 3]` は Array ですが、Sake のリテラル `[1, 2, 3]` は長さ固定の Tuple で、`Array.push` などに渡すと静的に拒否されます（[値と型](../03-values.md)）。`Integer[1, 2]`、`String[]`、`Point[p]` のような型付き Array は、要素の型が宣言された Array で、`Array.push`・`append`・`unshift`・`prepend`・`insert`・`concat`・`map!`・`fill`・`a[i] = v` などの書き込みが毎回検査されます（違う型は静的に `type` の問題、実行時は `TypeError`）。型付き Array にも、この章の操作がすべて使えます。`map`・`select`・`sort`・`first(a, n)`・`+` などが返す新しい Array には要素の型の宣言はありません。`dup` だけが要素の型を保ちます。

検査器は、1 つの Array（構築した場所）に対してプログラム全体で 1 つの要素型を与えます。`Array.map!` などの書き換えで別の型を入れると、以後その Array は両方の型を持つものとして扱われ、片方の型にしか合わない操作が `type`（partial）になります（[値と型](../03-values.md)）。

要素が無いことを nil で表す操作が 2 種類あります。「外した nil」（`x[k]`、`first`、`last`、`pop`、`shift`、`min`、`max`、`minmax`、`min_by`、`max_by`、`minmax_by`、`at`、`slice`、`slice!`、`dig`、`sample`、`delete_at`。空の Array や範囲外の添字）を未検査で使うのは `--strict=3` の `index-nil` の問題で、`--strict`（レベル 2）は見逃します。`find`、`index`、`find_index`、`rindex`、`bsearch`、`delete`、`uniq!` など、それ以外の nil はレベル 2 の `nil` の問題です（[概要](../01-overview.md)）。

Array に使える演算子は `+`、`-`、`*`、`==`、`!=`、`<`、`<=`、`>`、`>=`、`<=>`（2 つの Array を辞書順に比べる）と添字 `a[i]`、`a[i, n]`、`a[range]`、`a[i] = v` です。`Array.+(x, y)` などはその演算子を関数の形で呼ぶものです（[演算子と添字](../05-operators.md)）。要素を比べる操作（`sort`、`min`、`max`、`<` など）は、要素が互いに比べられる型でなければなりません。Integer と Float は混ぜて比べられ、Tuple は要素ごとに、クラスのインスタンスはその型の `<=>`（`include Comparable`）で比べます。

ブロックを取る操作は Ruby と同じ形で書きます（`Array.map(xs) { |x| x * 2 }`）。Ruby の Enumerator（ブロック無しの `each` など）はありません。ブロックが省ける操作（`each_with_index`、`each_slice`、`each_cons`）は、ブロック無しでは結果を Array で返します。

## Array[]

`Array[*Any]`

Array の Array を作ります。どの T でも `T[...]` が T の Array を作るのと同じで、各要素は Array でなければならず、書き込みのたびに検査されます（別の型のリテラルは静的なエラー、その他の値は `type` の問題、実行時は `TypeError`）。何でも入る Array は `Any[...]` です（[Kernel](Kernel.md)）。

```ruby
rows = Array[Any[1, 2], Any[3]]
Array.push(rows, Any[4, 5])
p(rows)                        # => [[1, 2], [3], [4, 5]]
```

```ruby error
p(Array[1])                    # !> Array[]: element 1 must be Array, got Integer
```

## new

`Array.new(Integer, [Any]) [{ }]`

長さ `n` の新しい Array を作ります。`Array.new(n)` は nil が n 個、`Array.new(n, v)` は同じ値 `v` が n 個（同じ 1 つの値を共有します。`Array.new(2, Any[])` の 2 要素は同じ Array です）、`Array.new(n) { |i| ... }` は添字 i ごとにブロックの値です。要素の型は nil、`v` の型、またはブロックの結果の型です。負の `n` は `ArgumentError`。

```ruby
p(Array.new(3))                        # => [nil, nil, nil]
p(Array.new(2, "a"))                   # => ["a", "a"]
p(Array.new(3) { |i| i * i })          # => [0, 1, 4]
rows = Array.new(2, Any[])
Array.push(Array.fetch(rows, 0), 1)
p(rows)                                # => [[1], [1]]
rows2 = Array.new(2) { |i| Any[] }
Array.push(Array.fetch(rows2, 0), 1)
p(rows2)                               # => [[1], []]
```

```ruby error
Array.new(-1)                          # !> ArgumentError: Array.new: negative size -1
```

## dup

`Array.dup(x)`

同じ要素を持つ新しい Array を返します（浅いコピー。要素は共有します）。型付き Array の複製は同じ要素の型を持つ型付き Array です。この章の他の操作が返す新しい Array と違い、要素型の宣言を保つのはこの操作だけです。

```ruby
xs = Integer[1, 2]
ys = Array.dup(xs)
Array.push(ys, 3)
p(xs)                          # => [1, 2]
p(ys)                          # => [1, 2, 3]
```

```ruby error
ys = Array.dup(Integer[1])
Array.push(ys, "s")            # !> Array.push: an element must be Integer, but is String
```

## to_a

`Array.to_a(x)`

主語そのもの（同じ Array）を返します。コピーではありません。`Tuple.to_a` や `Set.to_a`、`Hash.to_a` など他の型から Array を得る操作と形を揃えるためのものです。

```ruby
xs = Any[1, 2]
p(Array.to_a(xs))                          # => [1, 2]
p(Kernel.equal?(Array.to_a(xs), xs))       # => true
```

## length, size

`Array.length(x)`

`Array.size(x)`

要素の個数（Integer）。

```ruby
p(Array.size(Any[3, 1, 2]))      # => 3
p(Array.length(Any[]))           # => 0
```

## empty?

`Array.empty?(x)`

要素が 1 つも無いとき true。

```ruby
p(Array.empty?(Any[]))           # => true
p(Array.empty?(Any[1]))          # => false
```

## []

`Array.[](x, Any, [Integer])`

`a[i]`、`a[i, n]`、`a[range]` の関数形。`a[i]` は位置 `i`（Integer。負の値は末尾から）の要素で、範囲外なら nil です。その nil は「外した nil」で、未検査で使うのは `--strict=3` の `index-nil` の問題（レベル 2 では報告されません）。`a[i, n]` は位置 i から n 個、`a[range]` はその範囲の要素を新しい Array で返し、開始位置が末尾を越えているときは nil です。例外にしたいときは `Array.fetch` を使います。添字が Integer でも Range でもない値は `TypeError`。

```ruby
xs = Any[3, 1, 2]
p(xs[1])                       # => 1
p(xs[-1])                      # => 2
p(xs[9])                       # => nil
p(xs[1, 2])                    # => [1, 2]
p(xs[0..1])                    # => [3, 1]
p(xs[5, 1])                    # => nil
p(Array.[](xs, 0))             # => 3
p(Array.[](xs, 0, 2))          # => [3, 1]
```

## []=

`Array.[]=(x, Any, Any)`

`a[i] = v` の関数形。位置 `i` の要素を `v` に置き換え、`v` を返します。末尾より先に書くと、Ruby と同じく間が nil で埋まります。型付き Array では `v` の型が検査され（静的に `type`、実行時は `TypeError`）、nil は要素になれないので末尾より先への書き込みは `IndexError` です。負の添字が先頭より前なら `IndexError`。

```ruby
xs = Any[1]
xs[3] = 2
p(xs)                          # => [1, nil, nil, 2]
xs[-1] = 5
p(xs)                          # => [1, nil, nil, 5]
p(Array.[]=(xs, 0, 0))         # => 0
```

```ruby error
is = Integer[1]
is[3] = 2                      # !> IndexError: Array.[]=: index 3 is past the end of Integer[] (length 1); the gap would be nil
```

## at

`Array.at(x, Integer)`

位置 `i` の要素（`a[i]` と同じ。負の値は末尾から）。範囲外は nil で、「外した nil」としてレベル 3 だけが報告します。

```ruby
xs = Any[3, 1, 2]
p(Array.at(xs, 0))             # => 3
p(Array.at(xs, -1))            # => 2
p(Array.at(xs, 9))             # => nil
```

## fetch

`Array.fetch(x, Integer, [Any])`

位置 `i` の要素を返します。範囲外のときは、`default` があればそれを、無ければ `IndexError` を上げます。結果が nil になることはないので（default が nil でなければ）、`--strict` で添字の nil 検査を避けたいときに使います。結果の型は要素型（default があればその型との和）です。

```ruby
xs = Any[3, 1, 2]
p(Array.fetch(xs, 1))          # => 1
p(Array.fetch(xs, -1))         # => 2
p(Array.fetch(xs, 9, 0))       # => 0
```

```ruby error
Array.fetch(Any[3, 1, 2], 9)     # !> IndexError: Array.fetch: index 9 outside of array bounds: -3...3
```

## first, last

`Array.first(x, [Integer])`

`Array.last(x, [Integer])`

`first(a)` は先頭、`last(a)` は末尾の要素で、空の Array では nil（「外した nil」。レベル 3 だけが報告します）。`first(a, n)`、`last(a, n)` は先頭・末尾から n 個を新しい Array で返します（要素が足りなければあるだけ。nil にはなりません）。負の n は `ArgumentError`。

```ruby
xs = Any[3, 1, 2]
p(Array.first(xs))             # => 3
p(Array.last(xs))              # => 2
p(Array.first(xs, 2))          # => [3, 1]
p(Array.last(xs, 5))           # => [3, 1, 2]
p(Array.first(Any[]))        # => nil
p(Array.last(Any[], 2))      # => []
```

```ruby error
Array.first(Any[1], -1)      # !> ArgumentError: Array.first: negative size -1
```

## slice

`Array.slice(x, Integer|Range, [Integer])`

`a[i]`、`a[i, n]`、`a[range]` と同じ結果を返します: `slice(a, i)` は要素か nil、`slice(a, i, n)` と `slice(a, range)` は新しい Array か nil（開始位置が末尾を越えたとき）。`a[i]` と同じく、この nil は「外した nil」で、未検査で使うのは `--strict=3` の `index-nil` の問題です（レベル 2 では報告されません）。例外にしたいときは `Array.fetch` を使います。

```ruby
xs = Any[3, 1, 2]
p(Array.slice(xs, 1))          # => 1
p(Array.slice(xs, 1, 5))       # => [1, 2]
p(Array.slice(xs, 1..))        # => [1, 2]
p(Array.slice(xs, 9))          # => nil
y = Array.slice(xs, 0)
p(y + 1) if y                  # => 4
```

## dig

`Array.dig(x, Integer, *Any)`

位置 `i` の要素か nil（`a[i]` と同じ）。添字を 2 つ以上与えると、Ruby の `dig` のように入れ子を順に掘ります: 2 つ目以降の添字は 1 つ前で得た値に当て（Array なら Integer の位置、Hash ならそのキー）、途中で nil になればそのまま nil です。途中の値は Array、Tuple、Hash のどれかでなければならず、他の型（Integer、String、Record など）は静的に `type` の問題、検査を通さずに実行すれば `TypeError`（`Integer cannot be dug into (not an Array, a Tuple, or a Hash)`）です。Array や Tuple に Integer 以外の添字を当てると `TypeError`。nil は「外した nil」で、レベル 3 だけが報告します。

```ruby
xs = Any[Any[1, 2], Any[3]]
p(Array.dig(xs, 0))            # => [1, 2]
p(Array.dig(xs, 5))            # => nil
p(Array.dig(xs, 0, 1))         # => 2
p(Array.dig(xs, 1, 5))         # => nil
p(Array.dig(xs, 5, 0))         # => nil
p(Array.dig(Any[Hash.of(a: 1)], 0, :a))     # => 1
p(Array.dig(Any[[1, "x"]], 0, 1))        # => "x"
p(Array.dig(Any[[1, "x"]], 0, 5))        # => nil
```

```ruby error
p(Array.dig(Any[Any[1, 2]], 0, 1, 2))  # !> Array.dig: the value must be Array|Hash|Tuple, but is Integer
```

```ruby error
p(Array.dig(Any[Any[1]], 0, "k"))      # !> TypeError: Array.dig: an index into Array must be Integer, got String
```

## values_at

`Array.values_at(x, *Integer)`

与えた位置の要素を並べた新しい Array。範囲外の位置は nil になります（要素型は要素型と nil の和）。

```ruby
xs = Any[3, 1, 2]
p(Array.values_at(xs, 0, 2, 7))    # => [3, 2, nil]
```

## fetch_values

`Array.fetch_values(x, *Integer)`

与えた位置の要素を並べた新しい Array。範囲外の位置があれば `IndexError`（nil にはなりません）。

```ruby
p(Array.fetch_values(Any[3, 1, 2], 0, 2))    # => [3, 2]
```

```ruby error
Array.fetch_values(Any[3, 1, 2], 0, 9)       # !> IndexError: Array.fetch_values: index 9 outside of array bounds: -3...3
```

## push, append

`Array.push(x, *Any)`

`Array.append(x, *Any)`

末尾に値を追加して（何個でも）、主語を返します。その場で変更します。型付き Array では各値の型を検査します（静的に `type`、実行時は `TypeError`）。検査器は追加された値の型をその Array の要素型に加えます。Ruby の `<<` はありません。

```ruby
xs = Any[1]
p(Array.push(xs, 2, 3))        # => [1, 2, 3]
p(Array.append(xs, 4))         # => [1, 2, 3, 4]
```

```ruby error
Array.push(Integer[1, 2], "x")     # !> Array.push: an element must be Integer, but is String
```

## unshift, prepend

`Array.unshift(x, *Any)`

`Array.prepend(x, *Any)`

先頭に値を追加して（何個でも、与えた順のまま）、主語を返します。その場で変更します。型付き Array では型を検査します。

```ruby
xs = Any[3]
p(Array.unshift(xs, 1, 2))     # => [1, 2, 3]
p(Array.prepend(xs, 0))        # => [0, 1, 2, 3]
```

## insert

`Array.insert(x, Integer, *Any)`

位置 `i` の前に値を差し込み（何個でも）、主語を返します。`i` が長さと等しければ末尾に追加します。負の `i` は末尾から数えます（`-1` なら末尾に追加、`-size - 1` なら先頭）。`i` が長さより大きいとき、Ruby は間を nil で埋めますが、Sake では `IndexError` です（型付きでない Array でも。nil を黙って作らないためです）。`-size - 1` より小さい負の `i`（先頭より前）も `IndexError`。型付き Array では差し込む値の型を検査します（静的に `type`、実行時は `TypeError`）。

```ruby
xs = Any[1, 2, 3]
p(Array.insert(xs, 1, 9, 9))   # => [1, 9, 9, 2, 3]
p(Array.insert(xs, -2, 7))     # => [1, 9, 9, 2, 7, 3]
p(Array.insert(xs, 6, 8))      # => [1, 9, 9, 2, 7, 3, 8]
```

```ruby error
Array.insert(Any[1], 3, 2)   # !> IndexError: Array.insert: index 3 is past the end of the Array (length 1); the gap would be nil
```

```ruby error
Array.insert(Any[1, 2], -4, 0)   # !> IndexError: Array.insert: index -4 is before the start of the Array (length 2)
```

```ruby error
Array.insert(Integer[1], 0, "a")   # !> Array.insert: an element must be Integer, but is String
```

## concat

`Array.concat(x, Array)`

もう 1 つの Array の要素をすべて末尾に追加して、主語を返します。その場で変更します（`+` は新しい Array を作ります）。型付き Array では要素の型を検査します。

```ruby
xs = Any[1]
p(Array.concat(xs, Any[2, 3]))   # => [1, 2, 3]
```

```ruby error
Array.concat(Integer[1], Any["a"])   # !> Array.concat: an element must be Integer, but is String
```

## fill

`Array.fill(x, Any)`

すべての要素を `v` に置き換え、主語を返します（長さは変わりません）。Ruby の範囲やブロックの形はありません。型付き Array では `v` の型を検査します（静的に `type`、検査を通らずに実行すれば `TypeError`）。

```ruby
xs = Any[1, 2, 3]
p(Array.fill(xs, 0))           # => [0, 0, 0]
```

```ruby error
Array.fill(Integer[1], "a")    # !> Array.fill: an element must be Integer, but is String
```

## replace

`Array.replace(x, Array)`

主語の内容をもう 1 つの Array の要素で置き換え、主語を返します（`a = other` と違い、同じ Array を共有している場所すべてに見えます）。型付き Array では要素の型を検査します（静的に `type`、実行時は `TypeError`）。

```ruby
xs = Any[1, 2, 3]
ys = xs
p(Array.replace(xs, Any[9]))     # => [9]
p(ys)                              # => [9]
```

```ruby error
Array.replace(Integer[1], Any["a"])  # !> Array.replace: an element must be Integer, but is String
```

## pop

`Array.pop(x)`

末尾の要素を取り除いて返します。空の Array では nil（「外した nil」。レベル 3 だけが報告します）。Ruby の `pop(n)` はありません。

```ruby
xs = Any[1, 2]
p(Array.pop(xs))               # => 2
p(xs)                          # => [1]
p(Array.pop(Any[]))          # => nil
```

## shift

`Array.shift(x, [Integer])`

`shift(a)` は先頭の要素を取り除いて返し、空の Array では nil（「外した nil」。レベル 3 だけが報告します）。`shift(a, n)` は先頭から n 個を取り除いて新しい Array で返します（足りなければあるだけ。nil にはなりません）。負の n は `ArgumentError`。

```ruby
xs = Any[1, 2, 3, 4]
p(Array.shift(xs))             # => 1
p(Array.shift(xs, 2))          # => [2, 3]
p(xs)                          # => [4]
p(Array.shift(Any[]))        # => nil
p(Array.shift(Any[], 2))     # => []
```

## delete

`Array.delete(x, Any)`

`v` と `==` で等しい要素をすべて取り除き、`v` を返します。1 つも無ければ nil（レベル 2 の `nil` の問題）。

```ruby
xs = Any[1, 2, 1, 3]
p(Array.delete(xs, 1))         # => 1
p(xs)                          # => [2, 3]
p(Array.delete(xs, 42))        # => nil
```

## delete_at

`Array.delete_at(x, Integer)`

位置 `i` の要素を取り除いて返します。範囲外なら nil（「外した nil」。レベル 3 だけが報告します）。

```ruby
xs = Any[1, 2, 3]
p(Array.delete_at(xs, 1))      # => 2
p(xs)                          # => [1, 3]
p(Array.delete_at(xs, 99))     # => nil
```

## slice!

`Array.slice!(x, Integer|Range, [Integer])`

`slice` と同じものを返し、同時にそれを主語から取り除きます: `slice!(a, i)` は要素か nil、`slice!(a, i, n)` と `slice!(a, range)` は新しい Array か nil。nil は「外した nil」で、レベル 3 だけが報告します。

```ruby
xs = Any[1, 2, 3, 4]
p(Array.slice!(xs, 1, 2))      # => [2, 3]
p(xs)                          # => [1, 4]
p(Array.slice!(xs, 0))         # => 1
p(Array.slice!(xs, 5))         # => nil
p(Array.slice!(xs, 0..0))      # => [4]
p(xs)                          # => []
```

## clear

`Array.clear(x)`

すべての要素を取り除き、主語（空になった Array）を返します。

```ruby
xs = Any[1, 2]
p(Array.clear(xs))             # => []
p(xs)                          # => []
```

## each, each_entry

`Array.each(x) { }`

`Array.each_entry(x) { }`

各要素を順にブロックに渡し、主語を返します。ブロックは必須です（Ruby の Enumerator を返す形はありません）。`break v` でその場で終わり、`v` が結果になります。`each_entry` は `each` と同じです。

```ruby
xs = Any[1, 2, 3]
r = Array.each(xs) { |x| puts(x) }
# => 1
# => 2
# => 3
p(r)                                   # => [1, 2, 3]
p(Array.each(xs) { |x| break x if x == 2 })    # => 2
```

## each_with_index

`Array.each_with_index(x) [{ }]`

ブロックに要素と添字（0 から）を渡し、主語を返します。ブロック無しでは Ruby の Enumerator ではなく、`[要素, 添字]` の Tuple を並べた新しい Array を返します。

```ruby
xs = Any["a", "b"]
Array.each_with_index(xs) { |s, i| puts("#{i}:#{s}") }
# => 0:a
# => 1:b
p(Array.each_with_index(xs))           # => [["a", 0], ["b", 1]]
```

## each_index

`Array.each_index(x) { }`

添字 0 から長さ-1 までを順にブロックに渡し、主語を返します。

```ruby
xs = Any["a", "b"]
Array.each_index(xs) { |i| puts(i) }
# => 0
# => 1
```

## reverse_each

`Array.reverse_each(x) { }`

末尾から順に各要素をブロックに渡し、主語を返します。

```ruby
Array.reverse_each(Any[1, 2, 3]) { |x| puts(x) }
# => 3
# => 2
# => 1
```

## each_slice, each_cons

`Array.each_slice(x, Integer) [{ }]`

`Array.each_cons(x, Integer) [{ }]`

`each_slice(a, n)` は要素を n 個ずつに切った Array を、`each_cons(a, n)` は連続する n 個の窓を順にブロックに渡し、主語を返します。ブロック無しでは Ruby の Enumerator ではなく、それらの Array を並べた新しい Array を返します（`each_cons` で n が長さを越えると `[]`）。n は 1 以上でなければならず、0 や負の n は `ArgumentError` です。

```ruby
xs = Any[1, 2, 3]
p(Array.each_slice(xs, 2))             # => [[1, 2], [3]]
p(Array.each_cons(xs, 2))              # => [[1, 2], [2, 3]]
Array.each_slice(xs, 2) { |s| p(s) }
# => [1, 2]
# => [3]
p(Array.each_cons(xs, 2) { |s| s })    # => [1, 2, 3]
p(Array.each_cons(xs, 5))              # => []
```

```ruby error
Array.each_slice(Any[1], 0)          # !> ArgumentError: Array.each_slice: invalid slice size
```

## each_with_object

`Array.each_with_object(x, Any) { }`

各要素と `memo` をブロックに渡し（この順）、最後に `memo` を返します。`memo` の型が結果の型です。`reduce` と違い、ブロックの値は使いません（`memo` をその場で変更して溜めます）。

```ruby
xs = Any[1, 2, 3]
p(Array.each_with_object(xs, Any[]) { |x, acc| Array.push(acc, x * 2) })   # => [2, 4, 6]
```

## cycle

`Array.cycle(x, Integer) { }`

全要素を n 回繰り返してブロックに渡し、nil を返します。Ruby の無限に繰り返す形（引数無し）はなく、n は必須です。n が 0 以下なら何もしません。

```ruby
p(Array.cycle(Any[1, 2], 2) { |x| puts(x) })
# => 1
# => 2
# => 1
# => 2
# => nil
```

## map, collect

`Array.map(x) { }`

`Array.collect(x) { }`

各要素にブロックを適用した結果を並べた新しい Array。要素の型はブロックの結果の型で、要素型の宣言はありません（型付き Array から作っても、何でも追加できます）。

```ruby
xs = Any[1, 2, 3]
p(Array.map(xs) { |x| x * 2 })             # => [2, 4, 6]
p(Array.collect(xs) { |x| Integer.to_s(x) })   # => ["1", "2", "3"]
p(xs)                                      # => [1, 2, 3]
```

## map!, collect!

`Array.map!(x) { }`

`Array.collect!(x) { }`

各要素をブロックの値で置き換え、主語を返します。その場で変更します。検査器は 1 つの Array に 1 つの要素型を与えるので、元と違う型を入れると、以後その Array は両方の型を持つものとして扱われ、片方にしか合わない操作が `type` の問題になります。同じ型への写像に使い、型を変えるなら `map`（新しい Array）を使います。型付き Array では結果の型を検査します（静的に `type`、実行時は `TypeError`）。

```ruby
xs = Any[1, 2, 3]
p(Array.map!(xs) { |x| x * 2 })        # => [2, 4, 6]
p(Array.collect!(xs) { |x| x + 1 })    # => [3, 5, 7]
p(xs)                                  # => [3, 5, 7]
```

```ruby error
xs = Any[1, 2, 3]
Array.map!(xs) { |x| Integer.to_s(x) }
p(Array.sum(xs))               # !> Array.sum: an element must be Integer|Float|Rational|Complex, but can be String
```

## flat_map

`Array.flat_map(x) { }`

各要素にブロックを適用し、その結果の並びをつなげた新しい Array。ブロックは Array か Tuple を返さなければならず、他の値は実行時に `TypeError` です。Ruby のように Array 以外の値をそのまま並べることはありません。

```ruby
p(Array.flat_map(Any[1, 2]) { |x| Any[x, x * 10] })   # => [1, 10, 2, 20]
p(Array.flat_map(Any[1, 2]) { |x| [x, x] })             # => [1, 1, 2, 2]
```

```ruby error
Array.flat_map(Any[1]) { |x| x }    # !> TypeError: Array.flat_map: the block must return an Array or a Tuple, got Integer
```

## filter_map

`Array.filter_map(x) { }`

各要素にブロックを適用し、nil と false 以外の結果を並べた新しい Array（`map` と `compact` を合わせたもの。要素型から nil は除かれます）。

```ruby
xs = Any[1, 2, 3, 4]
p(Array.filter_map(xs) { |x| x * 10 if x > 2 })    # => [30, 40]
p(Array.filter_map(xs) { |x| x > 2 })              # => [true, true]
```

## select, filter, find_all

`Array.select(x) { }`

`Array.filter(x) { }`

`Array.find_all(x) { }`

ブロックが真（nil と false 以外）を返した要素を並べた新しい Array。

```ruby
xs = Any[1, 2, 3, 4]
p(Array.select(xs) { |x| x > 2 })      # => [3, 4]
p(Array.filter(xs) { |x| x > 2 })      # => [3, 4]
p(Array.find_all(xs) { |x| x > 2 })    # => [3, 4]
```

## select!, filter!, keep_if

`Array.select!(x) { }`

`Array.filter!(x) { }`

`Array.keep_if(x) { }`

ブロックが真を返した要素だけを残します（その場で変更）。`keep_if` は常に主語を返します。`select!`、`filter!` は 1 つも取り除かなかったとき nil を返し（Ruby と同じ）、その結果を未検査で使うのはレベル 2 の `nil` の問題です。

```ruby
xs = Any[1, 2, 3]
p(Array.select!(xs) { |x| x > 1 })     # => [2, 3]
p(Array.select!(xs) { |x| x > 1 })     # => nil
p(Array.keep_if(xs) { |x| x > 1 })     # => [2, 3]
p(Array.keep_if(xs) { |x| x > 2 })     # => [3]
p(xs)                                  # => [3]
```

## reject

`Array.reject(x) { }`

ブロックが真を返した要素を除いた新しい Array。

```ruby
p(Array.reject(Any[1, 2, 3, 4]) { |x| x > 2 })   # => [1, 2]
```

## reject!, delete_if

`Array.reject!(x) { }`

`Array.delete_if(x) { }`

ブロックが真を返した要素を取り除きます（その場で変更）。`delete_if` は常に主語を返します。`reject!` は 1 つも取り除かなかったとき nil を返し（Ruby と同じ）、その結果を未検査で使うのはレベル 2 の `nil` の問題です。

```ruby
xs = Any[1, 2, 3]
p(Array.reject!(xs) { |x| x > 2 })     # => [1, 2]
p(Array.reject!(xs) { |x| x > 2 })     # => nil
p(Array.delete_if(xs) { |x| x > 5 })   # => [1, 2]
p(Array.delete_if(xs) { |x| x > 1 })   # => [1]
```

## partition

`Array.partition(x) { }`

ブロックが真を返した要素の Array と、残りの Array の 2 要素 Tuple `[selected, rest]` を返します。多重代入で受けます。

```ruby
evens, odds = Array.partition(Any[1, 2, 3, 4]) { |x| Integer.even?(x) }
p(evens)                       # => [2, 4]
p(odds)                        # => [1, 3]
```

## group_by

`Array.group_by(x) { }`

ブロックの値をキーとし、そのキーになった要素の Array を値とする Hash を返します（最初に現れた順）。キーは Hash のキーになれる値でなければなりません（Regexp などは `TypeError`。[値と型](../03-values.md)）。

```ruby
p(Array.group_by(Any[1, 2, 3, 4]) { |x| x % 2 })    # => {1 => [1, 3], 0 => [2, 4]}
```

## chunk_while, slice_when

`Array.chunk_while(x) { }`

`Array.slice_when(x) { }`

隣り合う 2 要素 `(a, b)` をブロックに渡して並びを切り分け、切り分けた Array を並べた新しい Array を返します。`chunk_while` はブロックが真の間を同じ塊にまとめ、`slice_when` はブロックが真のところで切ります。

```ruby
xs = Any[1, 2, 4, 5, 7]
p(Array.chunk_while(xs) { |a, b| b == a + 1 })    # => [[1, 2], [4, 5], [7]]
p(Array.slice_when(xs) { |a, b| b != a + 1 })     # => [[1, 2], [4, 5], [7]]
```

## take, drop

`Array.take(x, Integer)`

`Array.drop(x, Integer)`

`take(a, n)` は先頭 n 個、`drop(a, n)` は先頭 n 個を除いた残りを新しい Array で返します（足りなければあるだけ）。負の n は `ArgumentError`。

```ruby
xs = Any[1, 2, 3, 4]
p(Array.take(xs, 2))           # => [1, 2]
p(Array.drop(xs, 2))           # => [3, 4]
p(Array.take(xs, 9))           # => [1, 2, 3, 4]
```

## take_while, drop_while

`Array.take_while(x) { }`

`Array.drop_while(x) { }`

先頭からブロックが真を返す間の要素を取る（`take_while`）、または捨てて残りを返す（`drop_while`）新しい Array。

```ruby
xs = Any[1, 2, 3, 4]
p(Array.take_while(xs) { |x| x < 3 })  # => [1, 2]
p(Array.drop_while(xs) { |x| x < 3 })  # => [3, 4]
```

## include?

`Array.include?(x, Any)`

`v` と `==` で等しい要素があるとき true。クラスのインスタンスはその型の等しさで比べます（[演算子と添字](../05-operators.md)）。

```ruby
p(Array.include?(Any[1, 2], 2))          # => true
p(Array.include?(Any[1, 2], nil))        # => false
p(Array.include?(Any[[1, 2]], [1, 2]))   # => true
```

## index, rindex

`Array.index(x, Any)`

`Array.rindex(x, Any)`

`v` と `==` で等しい最初（`index`）・最後（`rindex`）の要素の位置（Integer）。無ければ nil で、レベル 2 の `nil` の問題です。Ruby のブロック形はなく、条件で探すなら `find_index`。

```ruby
xs = Any[3, 1, 4, 1]
p(Array.index(xs, 1))          # => 1
p(Array.rindex(xs, 1))         # => 3
p(Array.index(xs, 9))          # => nil
```

```ruby error
i = Array.index(Any[1, 2], 2)
p(i + 1)                       # !> the operands may be nil
```

## find_index

`Array.find_index(x) { }`

ブロックが真を返す最初の要素の位置（Integer）。無ければ nil（レベル 2 の `nil` の問題）。

```ruby
p(Array.find_index(Any[3, 1, 4]) { |x| x > 3 })   # => 2
p(Array.find_index(Any[3, 1, 4]) { |x| x > 9 })   # => nil
```

## find, detect

`Array.find(x) { }`

`Array.detect(x) { }`

ブロックが真を返す最初の要素。無ければ nil で、レベル 2 の `nil` の問題です（空の Array でも nil です。要素が無いことと見つからないことを区別しません）。

```ruby
xs = Any[3, 1, 4]
p(Array.find(xs) { |x| x > 3 })        # => 4
p(Array.detect(xs) { |x| x > 30 })     # => nil
```

```ruby error
y = Array.find(Any[3, 1, 4]) { |x| x > 1 }
p(y + 1)                       # !> the operands may be nil
```

## rfind

`Array.rfind(x) { }`

ブロックが真を返す最後の要素。無ければ nil（レベル 2 の `nil` の問題）。Ruby 4.0 の `Array#rfind` に対応し、それより前の Ruby の上では使えません。

```ruby
p(Array.rfind(Any[3, 1, 4, 1, 5]) { |x| x < 4 })    # => 1
```

## bsearch, bsearch_index

`Array.bsearch(x) { }`

`Array.bsearch_index(x) { }`

ソート済みの Array を二分探索し、要素（`bsearch`）またはその位置（`bsearch_index`）を返します。Ruby と同じ 2 つのモードがあります: ブロックが true/false を返すなら true になる最初の要素（find-minimum）、Integer（`<=>` の結果）を返すなら 0 になる要素（find-any）。見つからなければ nil（レベル 2 の `nil` の問題）。ソートされていない Array では結果は定まりません。

```ruby
xs = Any[1, 3, 5, 7]
p(Array.bsearch(xs) { |x| x >= 4 })        # => 5
p(Array.bsearch_index(xs) { |x| x >= 4 })  # => 2
p(Array.bsearch(xs) { |x| 3 <=> x })       # => 3
p(Array.bsearch(xs) { |x| x >= 40 })       # => nil
```

## assoc, rassoc

`Array.assoc(x, Any)`

`Array.rassoc(x, Any)`

要素が Tuple や Array の並び（組の表）から、1 番目の項目が `k` に等しい（`assoc`）、2 番目の項目が `v` に等しい（`rassoc`）最初の要素を返します。無ければ nil（レベル 2 の `nil` の問題）。Ruby の `assoc` は Array の要素だけを見ますが、Sake の組は普通 Tuple なので Tuple も見ます。

```ruby
pairs = Any[[1, "a"], [2, "b"]]
p(Array.assoc(pairs, 2))       # => [2, "b"]
p(Array.rassoc(pairs, "a"))    # => [1, "a"]
p(Array.assoc(pairs, 9))       # => nil
```

## count

`Array.count(x, [Any]) [{ }]`

`count(a)` は要素の個数、`count(a, v)` は `v` と `==` で等しい要素の個数、`count(a) { |x| ... }` はブロックが真を返す要素の個数（Integer）。

```ruby
xs = Any[3, 1, 4, 1]
p(Array.count(xs))                     # => 4
p(Array.count(xs, 1))                  # => 2
p(Array.count(xs) { |x| x > 1 })       # => 2
```

## any?, all?, none?, one?

`Array.any?(x) { }`

`Array.all?(x) { }`

`Array.none?(x) { }`

`Array.one?(x) { }`

ブロックが真を返す要素が、1 つ以上ある（`any?`）、すべてである（`all?`）、1 つも無い（`none?`）、ちょうど 1 つである（`one?`）とき true。ブロックは必須です（Ruby のブロック無しの形やパターン引数はありません）。空の Array では `all?` と `none?` が true、`any?` と `one?` が false です。

```ruby
xs = Any[3, 1, 4]
p(Array.any?(xs) { |x| x > 3 })        # => true
p(Array.all?(xs) { |x| x > 0 })        # => true
p(Array.none?(xs) { |x| x > 4 })       # => true
p(Array.one?(xs) { |x| x > 3 })        # => true
p(Array.all?(Any[]) { |x| x > 0 })   # => true
```

```ruby error
Array.any?(Any[1])           # !> Array.any? requires a block
```

## sum

`Array.sum(x, [Any]) [{ }]`

要素の和。ブロックがあれば各要素をブロックの値に写してから足します。`init`（既定 0）から足し始め、空の Array では `init` そのものが結果です。要素と `init` は数（Integer、Float、Rational、Complex）か、`Arithmetic` を include して `+` を定義したクラスの値でなければならず、それ以外は静的に `type` の問題、実行時は `TypeError`（String の連結には `join` を使います）。Float の和が欲しいときは `sum(a, 0.0)` と書くと、空でも Float になります。

```ruby
p(Array.sum(Any[1, 2, 3]))                       # => 6
p(Array.sum(Any[]))                              # => 0
p(Array.sum(Any[], 0.0))                         # => 0.0
p(Array.sum(Any[1, 2.5]))                        # => 3.5
p(Array.sum(Any[1, 2], 10))                      # => 13
p(Array.sum(Any["a", "bb"]) { |s| String.size(s) })  # => 3
```

```ruby error
Array.sum(Any["a", "b"])     # !> Array.sum: an element must be Integer|Float|Rational|Complex, but is String
```

## reduce, inject

`Array.reduce(x, Any) { }`

`Array.inject(x, Any) { }`

`init` から始めて、累積値と各要素をブロックに渡し（この順）、その値を次の累積値にして、最後の累積値を返します。Ruby と違い `init` は必須です（省くと引数の個数の静的エラー）。空の Array では `init` が結果です。Ruby の Symbol を渡す形（`inject(:+)`）はありません。結果の型は `init` の型とブロックの結果の型の和です。

```ruby
p(Array.reduce(Any[1, 2, 3], 0) { |acc, x| acc + x })     # => 6
p(Array.inject(Any[1, 2, 3], 1) { |acc, x| acc * x })     # => 6
p(Array.reduce(Any[], 0) { |acc, x| acc + x })            # => 0
p(Array.reduce(Any["a", "b"], "") { |acc, x| acc + x })   # => "ab"
```

```ruby error
Array.reduce(Any[1, 2]) { |acc, x| acc + x }    # !> wrong number of arguments for Array.reduce (given 1, expected 2)
```

## min, max

`Array.min(x)`

`Array.max(x)`

最小・最大の要素。空の Array では nil（「外した nil」。レベル 3 だけが報告します）。要素は互いに比べられなければなりません: 比べられない型の組（Integer と String など）が要素型にあれば静的に `type` の問題（`elements compared in order may be (Integer, String), which cannot be compared`）、要素が nil になり得れば `nil` の問題です。検査器に見えない比較の失敗（`Float.NAN` など）は実行時に `ArgumentError`。Integer と Float は混ぜて比べられます。クラスのインスタンスはその型の `<=>`（`include Comparable`）で比べます。Ruby の `min(n)` やブロック形はありません。

```ruby
xs = Any[3, 1, 4, 1, 5]
p(Array.min(xs))               # => 1
p(Array.max(xs))               # => 5
p(Array.max(Any[2, 1.5]))    # => 2
p(Array.min(Any[]))          # => nil
```

```ruby error
Array.min(Any[1, "a"])       # !> Array.min: elements compared in order may be (Integer, String), which cannot be compared
```

```ruby error
Array.max(Any[1.0, Float.NAN])   # !> ArgumentError: Array.max: cannot compare elements of types Float
```

## minmax

`Array.minmax(x)`

最小と最大の 2 要素 Tuple `[min, max]`。空の Array では `[nil, nil]` で、各位置の型は要素型と nil の和です（`min`、`max` と同じ「外した nil」で、レベル 3 だけが報告します）。比較の規則は `min`、`max` と同じで、比べられない型の組は静的に `type` の問題、実行時の失敗は `ArgumentError`。

```ruby
p(Array.minmax(Any[3, 1, 4]))    # => [1, 4]
p(Array.minmax(Any[]))           # => [nil, nil]
lo, hi = Array.minmax(Any[3, 1, 4])
p(lo + hi)                         # => 5
```

## min_by, max_by

`Array.min_by(x) { }`

`Array.max_by(x) { }`

ブロックの値が最小・最大になる要素。空の Array では nil（「外した nil」。`min`、`max` と同じくレベル 3 だけが報告します）。ブロックの値どうしが比べられなければならず、比べられない型の組は静的に `type` の問題、検査器に見えない失敗は実行時に `ArgumentError`。

```ruby
ws = Any["bb", "a", "ccc"]
p(Array.min_by(ws) { |s| String.size(s) })     # => "a"
p(Array.max_by(ws) { |s| String.size(s) })     # => "ccc"
p(Array.min_by(Any[]) { |s| s })             # => nil
```

```ruby error
Array.min_by(Any[1, "a"]) { |x| x }  # !> Array.min_by: elements compared in order may be (Integer, String), which cannot be compared
```

## minmax_by

`Array.minmax_by(x) { }`

ブロックの値が最小になる要素と最大になる要素の 2 要素 Tuple。空の Array では `[nil, nil]`（各位置は「外した nil」で、レベル 3 だけが報告します）。比較の規則は `min_by`、`max_by` と同じです。

```ruby
lo, hi = Array.minmax_by(Any["bb", "a", "ccc"]) { |s| String.size(s) }
p([lo, hi])                    # => ["a", "ccc"]
```

## tally

`Array.tally(x)`

各要素をキー、その出現回数（Integer）を値とする Hash を返します（最初に現れた順）。要素は Hash のキーになれる値でなければなりません（`TypeError`）。

```ruby
p(Array.tally(Any["a", "b", "a"]))   # => {"a" => 2, "b" => 1}
```

## sort, sort!

`Array.sort(x)`

`Array.sort!(x)`

要素を昇順に並べた新しい Array（`sort`）、または主語をその場で並べ替えて返します（`sort!`）。Ruby の比較ブロックは取れず（静的エラー）、別の順で並べるには `sort_by` を使います。要素は互いに比べられなければなりません: 比べられない型の組が要素型にあれば静的に `type` の問題、要素が nil になり得れば `nil` の問題（nil を除くには `compact`）。検査器に見えない比較の失敗（`Float.NAN` など）は実行時に `ArgumentError`。Integer と Float は混ぜて比べられ、Tuple は要素ごとに、クラスのインスタンスはその型の `<=>` で比べます。

```ruby
xs = Any[3, 1, 2]
p(Array.sort(xs))              # => [1, 2, 3]
p(xs)                          # => [3, 1, 2]
p(Array.sort!(xs))             # => [1, 2, 3]
p(xs)                          # => [1, 2, 3]
p(Array.sort(Any[[2, "a"], [1, "b"]]))   # => [[1, "b"], [2, "a"]]
```

```ruby error
Array.sort(Any[1, 2]) { |a, b| b <=> a }     # !> Array.sort does not take a block
```

```ruby error
Array.sort(Any[1, "a"])      # !> Array.sort: elements compared in order may be (Integer, String), which cannot be compared
```

```ruby error
Array.sort(Any[1, nil])      # !> Array.sort: argument elements may be nil
```

```ruby error
Array.sort(Any[1.0, Float.NAN])  # !> ArgumentError: Array.sort: cannot compare elements of types Float
```

## sort_by, sort_by!

`Array.sort_by(x) { }`

`Array.sort_by!(x) { }`

ブロックの値（キー）の昇順に並べた新しい Array（`sort_by`）、または主語をその場で並べ替えて返します（`sort_by!`）。キーどうしが比べられなければならず、比べられない型の組は静的に `type` の問題、nil になり得るキーは `nil` の問題、検査器に見えない失敗は実行時に `ArgumentError`。降順は負のキーで、複数のキーは Tuple `[k1, k2]` で表します（Tuple は辞書順）。

```ruby
ws = Any["bb", "a", "ccc"]
p(Array.sort_by(ws) { |s| -String.size(s) })           # => ["ccc", "bb", "a"]
p(Array.sort_by(Any["bb", "a", "c"]) { |s| [String.size(s), s] })   # => ["a", "c", "bb"]
xs = Any[3, 1, 2]
p(Array.sort_by!(xs) { |x| -x })                       # => [3, 2, 1]
p(xs)                                                  # => [3, 2, 1]
```

## reverse, reverse!

`Array.reverse(x)`

`Array.reverse!(x)`

要素を逆順にした新しい Array（`reverse`）、または主語をその場で逆順にして返します（`reverse!`）。

```ruby
xs = Any[1, 2, 3]
p(Array.reverse(xs))           # => [3, 2, 1]
p(xs)                          # => [1, 2, 3]
p(Array.reverse!(xs))          # => [3, 2, 1]
p(xs)                          # => [3, 2, 1]
```

## rotate, rotate!

`Array.rotate(x, [Integer])`

`Array.rotate!(x, [Integer])`

先頭の n 個（既定 1）を末尾に回した新しい Array（`rotate`）、または主語をその場で回して返します（`rotate!`）。負の n は逆方向に回します。

```ruby
xs = Any[1, 2, 3]
p(Array.rotate(xs))            # => [2, 3, 1]
p(Array.rotate(xs, 2))         # => [3, 1, 2]
p(Array.rotate(xs, -1))        # => [3, 1, 2]
p(Array.rotate!(xs))           # => [2, 3, 1]
p(xs)                          # => [2, 3, 1]
```

## shuffle, shuffle!

`Array.shuffle(x)`

`Array.shuffle!(x)`

要素を無作為に並べ替えた新しい Array（`shuffle`）、または主語をその場で並べ替えて返します（`shuffle!`）。

```ruby
xs = Any[1, 2, 3]
p(Array.size(Array.shuffle(xs)))       # => 3
p(Array.sort(Array.shuffle!(xs)))      # => [1, 2, 3]
```

## sample

`Array.sample(x)`

無作為に選んだ 1 要素。空の Array では nil（「外した nil」。レベル 3 だけが報告します）。Ruby の `sample(n)` はありません。

```ruby
p(Array.sample(Any[7]))      # => 7
p(Array.sample(Any[]))       # => nil
```

## uniq, uniq!

`Array.uniq(x)`

`Array.uniq!(x)`

重複する要素（`==` で等しいもの。最初のものを残す）を除いた新しい Array（`uniq`）、または主語からその場で除いて返します（`uniq!`）。`uniq!` は 1 つも除かなかったとき nil を返し（Ruby と同じ）、その結果を未検査で使うのはレベル 2 の `nil` の問題です。Ruby のブロック形はありません。

```ruby
p(Array.uniq(Any[1, 2, 1, 3, 2]))    # => [1, 2, 3]
xs = Any[1, 1]
p(Array.uniq!(xs))                     # => [1]
p(Array.uniq!(xs))                     # => nil
```

```ruby error
p(Array.size(Array.uniq!(Any[1, 1])))    # !> Array.size: argument 1 may be nil
```

## compact, compact!

`Array.compact(x)`

`Array.compact!(x)`

nil の要素を除いた新しい Array（`compact`。要素型から nil が除かれます）、または主語からその場で除いて返します（`compact!`）。`compact!` は nil が 1 つも無かったとき nil を返し、その結果を未検査で使うのはレベル 2 の `nil` の問題です。

```ruby
p(Array.compact(Any[1, nil, 2]))     # => [1, 2]
xs = Any[1, nil]
p(Array.compact!(xs))                  # => [1]
p(Array.compact!(xs))                  # => nil
```

## flatten, flatten!

`Array.flatten(x)`

`Array.flatten!(x)`

入れ子の Array をすべて展開して平らにした新しい Array（`flatten`）、または主語をその場で平らにして返します（`flatten!`）。展開するのは Array だけで、Tuple は 1 つの値なので開きません（Ruby の `flatten` は開くので、Tuple が要素に来ると静的に `type` の問題として知らせます。開くには `Array.flat_map(xs) { |t| Tuple.to_a(t) }`）。`flatten!` は入れ子が無かったとき nil を返し、その結果を未検査で使うのはレベル 2 の `nil` の問題です。Ruby の深さ引数はありません。

```ruby
p(Array.flatten(Any[1, Any[2, Any[3]], 4]))     # => [1, 2, 3, 4]
xs = Any[1, Any[2]]
p(Array.flatten!(xs))                                 # => [1, 2]
p(Array.flatten!(xs))                                 # => nil
```

```ruby error
p(Array.flatten(Any[[1, 2], [3, 4]]))   # !> which flatten leaves whole
```

## zip

`Array.zip(x, *Array)`

主語の各要素と、他の Array の同じ位置の要素を組にした Tuple を並べた新しい Array。長さは主語の長さで、他の Array が短ければ nil で埋まり（その位置の型は要素型と nil の和）、長ければ余りは捨てます。Ruby と違い組は Array ではなく Tuple です。

```ruby
p(Array.zip(Any[1, 2, 3], Any["a", "b"]))              # => [[1, "a"], [2, "b"], [3, nil]]
p(Array.zip(Any[1, 2], Any["a", "b"], Any[:x, :y]))  # => [[1, "a", :x], [2, "b", :y]]
```

## product

`Array.product(x, Array)`

主語の要素と他の Array の要素のすべての組み合わせ `[a, b]`（Tuple）を並べた新しい Array。Ruby と違い、他の Array は 1 つだけで、組は Tuple です。

```ruby
p(Array.product(Any[1, 2], Any["a", "b"]))    # => [[1, "a"], [1, "b"], [2, "a"], [2, "b"]]
p(Array.product(Any[1], Any[]))               # => []
```

## transpose

`Array.transpose(x)`

Array の Array を行列と見て、行と列を入れ替えた新しい Array を返します。行は Array でも Tuple でもよく（`zip` の結果のような Tuple の並びも転置できます）、結果の行は Array です。行はすべて同じ長さでなければならず、長さが違えば `IndexError`。Array でも Tuple でもない要素は `TypeError`。

```ruby
p(Array.transpose(Any[Any[1, 2], Any[3, 4]]))   # => [[1, 3], [2, 4]]
p(Array.transpose(Array.zip(Any[1, 2], Any["a", "b"])))   # => [[1, 2], ["a", "b"]]
```

```ruby error
Array.transpose(Any[Any[1, 2], Any[3]])  # !> IndexError: Array.transpose: element size differs (1 should be 2)
```

## combination, repeated_combination

`Array.combination(x, Integer)`

`Array.repeated_combination(x, Integer)`

要素から n 個を選ぶ組み合わせ（`combination`。同じ要素は 1 度まで）、または重複を許す組み合わせ（`repeated_combination`）を Array で並べた新しい Array を返します（Ruby の Enumerator ではなく Array）。n が長さを越えると `combination` は `[]`。

```ruby
p(Array.combination(Any[1, 2, 3], 2))           # => [[1, 2], [1, 3], [2, 3]]
p(Array.repeated_combination(Any[1, 2], 2))     # => [[1, 1], [1, 2], [2, 2]]
p(Array.combination(Any[1, 2], 5))              # => []
```

## permutation, repeated_permutation

`Array.permutation(x, [Integer])`

`Array.repeated_permutation(x, Integer)`

要素から n 個を選んで並べる順列を Array で並べた新しい Array を返します。`permutation(a)` の n の既定は全要素です。`repeated_permutation` は同じ要素を繰り返して選べます（n は必須）。

```ruby
p(Array.permutation(Any[1, 2, 3], 2))   # => [[1, 2], [1, 3], [2, 1], [2, 3], [3, 1], [3, 2]]
p(Array.permutation(Any[1, 2]))         # => [[1, 2], [2, 1]]
p(Array.repeated_permutation(Any[1, 2], 2))     # => [[1, 1], [1, 2], [2, 1], [2, 2]]
```

## union, intersection, difference

`Array.union(x, *Array)`

`Array.intersection(x, *Array)`

`Array.difference(x, *Array)`

集合のように扱った結果の新しい Array を返します（順序は主語の順、`==` で比べます）。`union` は主語と他の Array すべての要素を重複を除いて並べ（要素型は全部の和）、`intersection` は他の Array すべてに含まれる要素だけを重複を除いて、`difference` は他の Array のどれにも含まれない要素を（重複はそのまま）残します。他の Array は何個でも（0 個でも）与えられます。

```ruby
a = Any[1, 2, 3]
b = Any[2, 3, 4]
p(Array.union(a, b))                   # => [1, 2, 3, 4]
p(Array.union(Any[1, 1]))            # => [1]
p(Array.intersection(a, b))            # => [2, 3]
p(Array.intersection(a, b, Any[3]))  # => [3]
p(Array.difference(a, b))              # => [1]
p(Array.difference(Any[1, 2, 2, 3], Any[2], Any[3]))    # => [1]
```

## intersect?

`Array.intersect?(x, Array)`

2 つの Array に共通する要素が 1 つでもあるとき true。

```ruby
p(Array.intersect?(Any[1, 2], Any[2, 3]))  # => true
p(Array.intersect?(Any[1, 2], Any[9]))     # => false
```

## join

`Array.join(x, [String])`

各要素を `to_s` で文字列にして、`sep`（既定 `""`）で区切ってつなげた String。`to_s` は `puts` と同じ規則で、nil は空、Array と Tuple は `inspect` の形、クラスのインスタンスはその型の `to_s` です（[値と型](../03-values.md)）。

```ruby
p(Array.join(Any[1, 2, 3], ", "))            # => "1, 2, 3"
p(Array.join(Any[1, "a", nil, :s, [1, 2]]))  # => "1as[1, 2]"
p(Array.join(Any[]))                         # => ""
```

## to_h

`Array.to_h(x)`

`[key, value]` の Tuple の並びから Hash を作ります。要素はすべて 2 要素の Tuple でなければならず（Array は不可）、他の値は `TypeError`。同じキーが複数あれば後のものが残ります。キーは Hash のキーになれる値でなければなりません。Ruby のブロック形はありません。

```ruby
p(Array.to_h(Any[[:a, 1], [:b, 2]]))     # => {a: 1, b: 2}
p(Array.to_h(Any[[1, "a"], [1, "b"]]))   # => {1 => "b"}
p(Array.to_h(Any[]))                     # => {}
```

```ruby error
Array.to_h(Any[1, 2])        # !> TypeError: Array.to_h: Array.to_h needs [key, value] Tuples, got Integer
```

## to_set

`Array.to_set(x)`

要素を集めた新しい Set（重複は 1 つに）。要素は Set の要素になれる値でなければなりません（`TypeError`）。

```ruby
p(Array.to_set(Any[1, 2, 1]))    # => Set[1, 2]
```

## pack

`Array.pack(x, String)`

Ruby の `Array#pack`。要素を書式 `fmt` に従ってバイト列（String）にします。不正な書式は `ArgumentError`、書式に合わない要素（`"C*"` に String など）は `TypeError`。逆は `String.unpack`。

```ruby
p(Array.pack(Any[65, 66], "C*"))     # => "AB"
p(Array.pack(Any[1, 2], "n*"))       # => "\x00\x01\x00\x02"
```

```ruby error
Array.pack(Any["a"], "C")    # !> TypeError: Array.pack: no implicit conversion of String into Integer
```

## +, -, *

`Array.+(x, Any)`

`Array.-(x, Any)`

`Array.*(x, Any)`

`a + b` は 2 つの Array をつなげた新しい Array（要素型は和。`concat` はその場で変更します）。`a - b` は `b` に含まれる要素（`==` で等しいもの）をすべて除いた新しい Array（`difference` と同じ）。`a * n` は `a` を n 回繰り返した新しい Array で、負の n は `ArgumentError`。右側は `+`、`-` では Array、`*` では Integer でなければならず、Tuple や String（Ruby の `a * ","` は `join`）は静的に `type` の問題です。

```ruby
a = Any[1, 2, 3]
b = Any[2, 3, 4]
p(a + b)                       # => [1, 2, 3, 2, 3, 4]
p(a - b)                       # => [1]
p(Any[1, 2, 2] - Any[2])   # => [1]
p(a * 2)                       # => [1, 2, 3, 1, 2, 3]
p(Array.+(a, Any[9]))        # => [1, 2, 3, 9]
p(Array.*(a, 0))               # => []
```

```ruby error
p(Any[1] + [2])              # !> which the left operand's type does not support
```

## ==, !=

`Array.==(x, Any)`

`Array.!=(x, Any)`

2 つの Array が同じ長さで、各位置の要素が `==` で等しいときに true（`!=` はその否定）。右側が Array 以外の値（Tuple や nil）なら等しくありません。`[1, 2]` は Tuple なので `Any[1, 2]` とは等しくありません。

```ruby
a = Any[1, 2, 3]
p(a == Any[1, 2, 3])         # => true
p(a != Any[1, 2])            # => true
p(a == [1, 2, 3])              # => false
p(a == nil)                    # => false
p(Array.==(a, a))              # => true
```

## <, <=, >, >=

`Array.<(x, Any)`

`Array.<=(x, Any)`

`Array.>(x, Any)`

`Array.>=(x, Any)`

2 つの Array を辞書順に比べます: 先頭から順に要素を比べ、最初に違った位置で決まり、すべて等しければ短い方が小さい。要素は互いに比べられる型でなければならず、比べられない組は静的に `type` の問題（`which cannot be compared`）、実行時は `ArgumentError`。右側は Array でなければなりません（Tuple は `type` の問題）。

```ruby
p(Any[1, 2] < Any[1, 3])           # => true
p(Any[1, 2] < Any[1, 2, 0])        # => true
p(Any[2] > Any[1, 9])              # => true
p(Any[1, 2] <= Any[1, 2])          # => true
p(Array.>=(Any[1], Any[1]))        # => true
```

```ruby error
p(Any[1, "a"] < Any[1, 2])         # !> which cannot be compared
```

## <=>

`Array.<=>(x, Any)`

辞書順の比較の結果を -1、0、1 で返します。比較の規則は `<` と同じです。比べられない組は静的に `type` の問題で、検査を通らずに実行すれば（`--strict=0`）nil になります（`<` などは `ArgumentError`）。

```ruby
a = Any[1, 2, 3]
p(a <=> Any[1, 2, 4])        # => -1
p(a <=> a)                     # => 0
p(Array.<=>(a, Any[1]))      # => 1
```

# Enum

Enum は Ruby の Enumerable を短い名前にした module で、prelude（`sakelib/prelude.sake`。どのプログラムも最初に読む）が Sake で定義しています。`Enum.map(x) { }` などの関数は mixin 関数で、第 1 引数の型でディスパッチします（[プログラムの構造](../02-program.md)の「module の関数の呼び方」）。Array・Hash・Set・Range は Enum を include していて、自分の操作で答えます: `Enum.map(xs)` は xs が Array なら `Array.map(xs)`、`Enum.each(h) { |k, v| }` は `Hash.each` です。組み込み型には何も写されません。それ以外の型（Integer、Tuple、String）の値を渡すのは実行前に `type` の問題、実行時は `TypeError` です。Tuple は Enum を include しません（長さと位置ごとの型が決まっているので、添字と分解で扱います）。

自分のクラスは `include Enum` と `def each(c) = ... yield(v) ...` を書けば参加します。Enum の他の関数はすべて `each` の上に書かれているので、クラスに写され（[include](../02-program.md)）、`C.map(c) { }`、`C.count(c)`、`Enum.first(c)` のどれでも呼べます。クラス自身が同名の関数を定義していればそれが勝ちます。

```ruby
class Deck
  include Enum
  attr_reader cards
  def each(d) = Array.each(@cards) { |c| yield(c) }
end
d = Deck.new(Any["A", "K", "Q", "J"])
p(Deck.map(d) { |c| String.downcase(c) })     # => ["a", "k", "q", "j"]
p(Enum.count(d))                              # => 4
p(Enum.select(Any[3, 1, 2]) { |v| v > 1 })  # => [3, 2]
```

```ruby error
p(Enum.map(5) { |v| v })                      # !> Enum.map dispatches on its first argument, which is Integer; the types that include Enum are Array, Hash, Set, Range
```

結果が nil になりうる関数（`find`、`first`、`min_by`、`max_by`）は、自分のクラスの写しでは `nil | T` を返し、検査しないで使うと level 2 で報告されます。組み込み型にディスパッチしたときは、その型の操作の規則に従います（`Array.first` の「外れの nil」は level 3）。以下の各節は Enum 自身の定義を述べ、組み込み型では同名の操作（[Array](Array.md)、[Hash](Hash.md)、[Set](Set.md)、[Range](Range.md)）が走ります。

## each

`Enum.each(x)`

必須の関数です。Enum を include するクラスが `def each(c)` を定義し、各要素に `yield(v)` します（Hash のように 2 つ渡してもよい）。`Enum.each(x) { }` は x の型の `each` にディスパッチします。定義していないクラスは、呼び出しが届く場所で `type` の問題、実行時は `NotImplementedError` です。

```ruby
Enum.each(Hash.of(a: 1, b: 2)) { |k, v| puts("#{k}: #{v}") }
# => a: 1
# => b: 2
```

## map

`Enum.map(x) { }`

各要素をブロックの値に写した Array を返します。

```ruby
p(Enum.map(1..3) { |v| v * v })               # => [1, 4, 9]
p(Enum.map(Set.of(1, 2)) { |v| -v })             # => [-1, -2]
```

## select, filter

`Enum.select(x) { }`

`Enum.filter(x) { }`

ブロックが真を返した要素の Array を返します。

```ruby
p(Enum.select(Any[1, 2, 3, 4]) { |v| v % 2 == 0 })   # => [2, 4]
p(Enum.filter(1..6) { |v| v > 4 })                     # => [5, 6]
```

## reject

`Enum.reject(x) { }`

ブロックが偽を返した要素の Array を返します。

```ruby
p(Enum.reject(Any[1, 2, 3, 4]) { |v| v % 2 == 0 })   # => [1, 3]
```

## filter_map

`Enum.filter_map(x) { }`

各要素にブロックを適用し、真の結果だけを集めた Array を返します（nil と false は落ちます）。

```ruby
p(Enum.filter_map(Any["1", "x", "3"]) { |s| String.to_i(s) if String.match?(s, /\A\d+\z/) })   # => [1, 3]
```

## flat_map

`Enum.flat_map(x) { }`

ブロックが返す Array（か Tuple）を 1 段つなげた Array を返します。

```ruby
p(Enum.flat_map(Any[1, 2]) { |v| Any[v, v * 10] })   # => [1, 10, 2, 20]
```

## find, detect

`Enum.find(x) { }`

`Enum.detect(x) { }`

ブロックが真を返す最初の要素を返します。無ければ nil（自分のクラスでは level 2、`Array.find` などでは level 2）。

```ruby
p(Enum.find(Any[3, 8, 5]) { |v| v > 4 })    # => 8
p(Enum.detect(1..3) { |v| v > 9 })            # => nil
```

## reduce, inject

`Enum.reduce(x, init) { }`

`Enum.inject(x, init) { }`

`init` から始めて、各要素でブロックを `yield(acc, v)` と呼び、最後の累積値を返します。Ruby と違い、初期値は省略できません（要素型だけから結果の型が決まらないため。[Array](Array.md) の `reduce` と同じ）。

```ruby
p(Enum.reduce(Any[1, 2, 3], 0) { |acc, v| acc + v })     # => 6
p(Enum.inject(1..4, 1) { |acc, v| acc * v })               # => 24
```

## sum

`Enum.sum(x, [init]) [{ }]`

要素の和（ブロックがあればブロックの値の和）を返します。`init`（既定 0）から足し始めます。組み込み型では要素は数か `Arithmetic` を include する型の値でなければなりません（[Array](Array.md)）。

```ruby
p(Enum.sum(1..4))                             # => 10
p(Enum.sum(Any[1, 2, 3]) { |v| v * 10 })      # => 60
```

## count

`Enum.count(x) [{ }]`

要素の数、ブロックがあればブロックが真を返した要素の数を返します。

```ruby
p(Enum.count(Set.of(1, 2, 3)))                   # => 3
p(Enum.count(1..10) { |v| v % 3 == 0 })       # => 3
```

## include?

`Enum.include?(x, v)`

`==` で等しい要素があれば true。

```ruby
p(Enum.include?(1..5, 3))                     # => true
p(Enum.include?(Any["a"], "b"))             # => false
```

## any?, all?, none?, one?

`Enum.any?(x) [{ }]`

`Enum.all?(x) [{ }]`

`Enum.none?(x) [{ }]`

`Enum.one?(x) [{ }]`

ブロックが真を返す要素が 1 つ以上ある / すべて / 無い / ちょうど 1 つ、のとき true。ブロックが無ければ要素自身の真偽を見ます。

```ruby
xs = Any[1, 2, 3]
p(Enum.any?(xs) { |v| v > 2 })                # => true
p(Enum.all?(xs) { |v| v > 2 })                # => false
p(Enum.none?(xs) { |v| v > 5 })               # => true
p(Enum.one?(xs) { |v| v > 2 })                # => true
```

## min_by, max_by

`Enum.min_by(x) { }`

`Enum.max_by(x) { }`

ブロックの値が最小 / 最大の要素を返します。空なら nil。ブロックの値は互いに比べられる型でなければなりません（検査器が静的に見ます）。

```ruby
words = Any["pear", "fig", "banana"]
p(Enum.min_by(words) { |w| String.length(w) })   # => "fig"
p(Enum.max_by(words) { |w| String.length(w) })   # => "banana"
```

## sort_by

`Enum.sort_by(x) { }`

ブロックの値の昇順に並べた Array を返します。

```ruby
p(Enum.sort_by(Any["bb", "a", "ccc"]) { |s| -String.length(s) })   # => ["ccc", "bb", "a"]
```

## to_a

`Enum.to_a(x)`

要素を並べた新しい Array を返します。

```ruby
p(Enum.to_a(1..3))                            # => [1, 2, 3]
p(Enum.to_a(Hash.of(a: 1)))                      # => [[:a, 1]]
```

## first

`Enum.first(x, [n])`

最初の要素（空なら nil）、`n` を与えれば最初の `n` 個の Array を返します。

```ruby
p(Enum.first(Any[7, 8, 9]))                 # => 7
p(Enum.first(1..10, 3))                       # => [1, 2, 3]
```

## take, drop

`Enum.take(x, n)`

`Enum.drop(x, n)`

最初の `n` 個の Array / 最初の `n` 個を除いた Array を返します。

```ruby
p(Enum.take(1..5, 2))                         # => [1, 2]
p(Enum.drop(1..5, 2))                         # => [3, 4, 5]
```

## group_by

`Enum.group_by(x) { }`

ブロックの値をキーに、同じ値になった要素の Array を値にした Hash を返します。

```ruby
p(Enum.group_by(1..6) { |v| v % 3 })          # => {1 => [1, 4], 2 => [2, 5], 0 => [3, 6]}
```

## partition

`Enum.partition(x) { }`

ブロックが真を返した要素の Array と、偽を返した要素の Array の Tuple `[yes, no]` を返します。

```ruby
yes, no = Enum.partition(1..6) { |v| v > 3 }
p(yes)                                        # => [4, 5, 6]
p(no)                                         # => [1, 2, 3]
```

## each_with_object

`Enum.each_with_object(x, memo) { }`

各要素でブロックを `yield(v, memo)` と呼び、`memo` を返します。

```ruby
p(Enum.each_with_object(Any[1, 2], Any[]) { |v, m| Array.unshift(m, v) })   # => [2, 1]
```

## compact

`Enum.compact(x)`

nil を除いた要素の Array を返します。

```ruby
p(Enum.compact(Any[1, nil, 2]))             # => [1, 2]
```

# Tuple

Tuple は長さが固定で、位置ごとに型が決まった並びです。リテラル `[1, "a"]` が Tuple を作ります（Ruby の `[1, "a"]` は Array ですが、Sake では `Any[1, "a"]` が Array です。[値と型](../03-values.md)）。要素の個数と各位置の型は値の型の一部で、検査器は添字の範囲と位置の型を静的に見ます。伸ばす・縮めることはできません。可変長の並びには Array を使います。

多重代入 `a, b = t` と Tuple パターン `in [Integer, String]` が Tuple を分解します。関数の `return a, b` は Tuple を返します。

Tuple に使える演算子は `==`、`!=`、`<`、`<=`、`>`、`>=`、`<=>`（2 つの Tuple を辞書順に比べる）と添字 `t[i]`、`t[i] = v` です。ここに挙げた `Tuple.<(x, y)` などは、その演算子を関数の形で呼ぶものです（[演算子と添字](../05-operators.md)）。

## Tuple[]

`Tuple[*Any]`

**Tuple の Array** を作ります（Tuple そのものではありません）。`Integer[]` や `String[]` と同じ型付き Array で、要素はすべて Tuple でなければならず、`Array.push` などの書き込みも毎回検査されます。Tuple 以外の要素は静的に `type` の問題、実行時は `TypeError` です。空の Tuple の Array は `Tuple[]` です。

```ruby
pairs = Tuple[[1, "a"], [2, "b"]]
Array.push(pairs, [3, "c"])
p(pairs)                   # => [[1, "a"], [2, "b"], [3, "c"]]
p(Array.size(Tuple[]))     # => 0
```

```ruby error
Array.push(Tuple[], 1)     # !> Array.push: an element must be Tuple, but is Integer
```

## []

`Tuple.[](x, Any)`

`t[i]` の関数形。位置 `i`（Integer。負の値は末尾から）の要素を返します。戻り値の型はその位置の型です。Tuple の長さは型の一部なので、範囲外の添字は Array のように nil にならず、静的に `type` の問題（`the index is outside the Tuple`）、実行時は `IndexError` です。添字に Range は使えません（`TypeError`）。

```ruby
t = [1, "a", 2.5]
p(t[0])                    # => 1
p(t[-1])                   # => 2.5
p(Tuple.[](t, 1))          # => "a"
```

```ruby error
t = [1, 2]
p(t[5])                    # !> the index is outside the Tuple
```

## []=

`Tuple.[]=(x, Any, Any)`

`t[i] = v` の関数形。位置 `i` の要素を `v` に置き換え、`v` を返します。その位置の型と違う型の値は静的に `type` の問題、実行時は `TypeError` です。範囲外の添字は `IndexError`。

```ruby
t = [1, "a"]
t[0] = 10
Tuple.[]=(t, 1, "b")
p(t)                       # => [10, "b"]
```

```ruby error
t = [1, 2]
t[0] = "x"                 # !> the value must be Integer, but is String
```

## length, size

`Tuple.length(x)`

`Tuple.size(x)`

要素の個数（Integer）。Tuple の長さは型から分かるので、検査器にとっては定数です。

```ruby
p(Tuple.size([1, "a", 2.5]))     # => 3
p(Tuple.length([]))              # => 0
```

## max, min

`Tuple.max(x)`

`Tuple.min(x)`

要素のうち最大・最小のものを返します（Ruby の `[a, b].max`）。各位置の型は分かっているので、要素が互いに比べられるかは静的に見ます: 比べられない組（Integer と String など）は `type` の問題（`elements compared in order may be (Integer, String), which cannot be compared`）、nil になり得る位置は `nil` の問題です。検査器に見えない比較の失敗（`Float.NAN` など）は実行時に `ArgumentError`。Integer と Float は混ぜて比べられます。空の Tuple `[]` では nil です。要素が クラスのインスタンスなら、その型の `<=>`（`include Comparable`）で比べます。結果の型は各位置の型の和で、空でない Tuple では nil になりません。

```ruby
p(Tuple.max([3, 1, 2]))          # => 3
p(Tuple.min([3, 1, 2]))          # => 1
p(Tuple.max([2, 1.5]))           # => 2
p(Tuple.max([3, 1]) + 1)         # => 4
p(Tuple.max([]))                 # => nil
```

```ruby error
p(Tuple.max([1, "a"]))           # !> Tuple.max: elements compared in order may be (Integer, String), which cannot be compared
```

```ruby error
p(Tuple.max([1.0, Float.NAN]))   # !> ArgumentError: Tuple.max: cannot compare elements of types Float
```

## minmax

`Tuple.minmax(x)`

最小と最大の 2 要素の Tuple `[min, max]` を返します。比較の規則は `min`、`max` と同じです（比べられない組は静的に `type` の問題）。

```ruby
lo, hi = Tuple.minmax([3, 1, 2])
p([lo, hi])                      # => [1, 3]
```

## to_a

`Tuple.to_a(x)`

同じ要素を持つ新しい Array を返します。元の Tuple とは独立で、Array の方は伸ばせます。要素の型は Tuple の各位置の型の和になります。

```ruby
t = [1, "a"]
a = Tuple.to_a(t)
Array.push(a, :x)
p(a)                             # => [1, "a", :x]
p(t)                             # => [1, "a"]
```

## ==, !=

`Tuple.==(x, Any)`

`Tuple.!=(x, Any)`

2 つの Tuple が同じ長さで、各位置の要素が `==` で等しいときに true（`!=` はその否定）。右側が Tuple 以外の値（Array や nil）なら等しくありません。`Any[1, 2]` と `[1, 2]` は型が違うので等しくありません。

```ruby
p([1, 2] == [1, 2])              # => true
p([1, 2] != [1, 2, 3])           # => true
p([1, 2] == Any[1, 2])         # => false
```

## <, <=, >, >=

`Tuple.<(x, Any)`

`Tuple.<=(x, Any)`

`Tuple.>(x, Any)`

`Tuple.>=(x, Any)`

2 つの Tuple を辞書順に比べます: 先頭から順に要素を比べ、最初に違った位置で決まり、すべて等しければ短い方が小さい。各位置の組は互いに比べられる型でなければならず、比べられない組は静的に `type` の問題（`elements compared in order may be (Integer, String)`）です。右側は Tuple でなければなりません。

```ruby
p([1, 2] < [1, 3])               # => true
p([2] > [1, 9])                  # => true
p([1] < [1, 0])                  # => true
p(Tuple.<=([1, 2], [1, 2]))      # => true
```

```ruby error
p([1, 2] < [1, "a"])             # !> which cannot be compared
```

## <=>

`Tuple.<=>(x, Any)`

辞書順の比較の結果を -1、0、1 で返します。比較の規則は `<` と同じです。`Array.sort_by` のキーに Tuple を返すと、この順で並びます。

```ruby
p([1, 2] <=> [1, 2])             # => 0
p([1, 2] <=> [1, 2, 3])          # => -1
p(Array.sort_by(Any["bb", "a", "c"]) { |s| [String.size(s), s] })   # => ["a", "c", "bb"]
```

# Range

Range は 2 つの端と、終端を含むかどうかの印の組です: `1..5` は 5 を含み、`1...5` は含みません。端は Integer、Float、String、nil のいずれかです（[値と型](../03-values.md)）: `1..` は終端の無い Range、`..5` は始端の無い Range です。終端の無い Range を行末に書くときは `r = (3..)` と括弧で囲みます。Ruby と同じく、`3..` の直後の改行は次の行へ続いてしまうからです。型の違う端の組（`1.."a"`）は実行時に `ArgumentError`。Range は値であり、変更する操作はありません。すべての結果は新しい値です。

検査器は端の型を Range とともに持ち（`Range[Integer]`）、その型でどの操作が使えるかが決まります:

- **値を順に辿る操作**（`each`、`map`、`to_a`、`select`、`find`、`count` など）には Integer か String で始まる Range が要ります。`"a".."e"` は Ruby の `String#succ` で進みます。それ以外の型の Range（`1.0..2.0` など）は静的に `type` の問題（`the Range's first value must be Integer|String, but is Float`）、実行時は `TypeError` です。
- `step`、`sum`、`size` は Integer で始まる Range だけを取ります。String の Range は `type` の問題です。
- Range 全体を使う操作（`to_a`、`map`、`sum`、`last`、`min`、`max` など）には**有限**の Range が要ります。終端の無い Range には `RangeError`（`cannot do this on an endless Range 1..`）を投げます。途中で止まれる操作（`each`、`find`、`take`、`first(r, n)`、`each_slice`、`bsearch`）は終端の無い Range も受け取り、`each` は `break` するまで走ります。
- `cover?`、`overlap?`、`begin`、`end`、`exclude_end?` は端だけを見るので、Float や終端の無いものも含めてどんな Range でも使えます。`include?` と `member?` も数の Range では同じですが、String の Range は Ruby と同じく辿ります。
- 始端が終端より大きい Range（`5..1`）には値がありません: 辿っても何も起きず、`to_a` は `[]`、`min` は nil です。`first`、`last`、`begin`、`end` は端をそのまま返します。

Range に使える演算子は `==` と `!=` です（2 つの Range は端と `exclude_end?` が同じなら等しい）。Range での添字（`a[1..3]`、`s[0...2]`）は Array と String の操作です（[演算子と添字](../05-operators.md)）。Range は Hash のキーや Set の要素にはできません（`TypeError`）。nil になりうる結果（`first`、`last`、`min`、`max`、`begin`、`end`、`find`、`find_index`、`bsearch`、`min_by`、`max_by`）の型は `T | nil` で、未検査のまま使うと `--strict`（レベル 2）が報告します。レベル 3 の「外れの nil」に当たるのは `minmax` と `minmax_by` の Tuple の要素だけです（`a, b = tuple` と同じ扱い）。

操作の多くは Ruby の Enumerable のメソッドです。Ruby と違い、署名に `{ }` のある操作のブロックは**必須**（例外は `count` と `sum` で、ブロックは省略可能）、`reduce` と `inject` には初期値が要り、`each` や `map` などのブロックはちょうど 1 つの引数を取ります（`each_with_index`、`each_with_object`、`chunk_while`、`slice_when` は 2 つ）。引数の数が違うブロックは実行時に `ArgumentError` です。

## begin, end

`Range.begin(x)`

`Range.end(x)`

書かれたままの 2 つの端です（Ruby の `r.begin`、`r.end`）。`end` は除外される終端でも書かれた値を返します（`Range.end(1...5)` は 5、`Range.max(1...5)` は 4）。結果の型は `T | nil` です: 終端の無い Range の `end` と始端の無い Range の `begin` は nil なので、算術に使う前の検査を `--strict` が求めます。

```ruby
p(Range.begin(1..5))         # => 1
p(Range.end(1...5))          # => 5
p(Range.end(1..))            # => nil
p(Range.begin("a".."z"))     # => "a"
```

```ruby error
x = Range.begin(1..5)
p(x + 1)                     # !> the operands may be nil
```

## exclude_end?

`Range.exclude_end?(x)`

3 つの点で書いた Range（`1...5`）なら true、2 つ（`1..5`、`1..`）なら false。

```ruby
p(Range.exclude_end?(1..5))      # => false
p(Range.exclude_end?(1...5))     # => true
p(Range.exclude_end?(1..))       # => false
```

## ==, !=

`Range.==(x, Any)`

`Range.!=(x, Any)`

両端が `==` で等しく、`exclude_end?` も一致するときに 2 つの Range は等しい（`!=` はその否定）。`1..5` と `1...5` は違います。右側が Range でない値（Integer、nil）とは等しくなく、関数形も演算子と同じです: `(1..5) == 5` も `Range.==(1..5, 5)` も false。

```ruby
p((1..5) == (1..5))          # => true
p((1..5) == (1...5))         # => false
p((1..5) != (1...6))         # => true
p((1..5) == 5)               # => false
p(Range.==(1..5, 1..5))      # => true
p(Range.==(1..5, 5))         # => false
p(Range.!=(1..5, nil))       # => true
```

## include?, cover?, member?

`Range.include?(x, Any)`

`Range.cover?(x, Any)`

`Range.member?(x, Any)`

値が Range にあれば true。`cover?` は Ruby の `cover?` です: 端と比べるだけで（`begin <= v <= end`、`...` なら `< end`）Range を辿らないので、終端の無い Range、始端の無い Range、Float の Range でも使え、Integer の Range に Float も見つかります。`include?` と `member?` は Ruby の `include?` です: 数の Range では `cover?` と同じですが、**String の Range は `String#succ` で辿る**ので、`"a".."z"` に `"m"` は含まれ `"mm"` は含まれません（`cover?` は `"a" <= "mm" <= "z"` なので true）。端の無い String の Range は `TypeError`（`cannot determine inclusion in beginless/endless ranges`）。端と型の違う値（`1..5` に `"a"`、nil）は false。値に Range を渡したとき、`cover?` は Ruby と同じく全体が内側にあるかを答え、`include?` と `member?` は false です。

```ruby
p(Range.include?(1..5, 5))         # => true
p(Range.include?(1...5, 5))        # => false
p(Range.cover?(1..5, 2.5))         # => true
p(Range.member?(1..5, 0))          # => false
p(Range.include?(1.., 100))        # => true
p(Range.include?("a".."z", "m"))   # => true
p(Range.include?("a".."z", "mm"))  # => false
p(Range.cover?("a".."z", "mm"))    # => true
p(Range.include?(1..5, "a"))       # => false
p(Range.cover?(1..5, 2..3))        # => true
p(Range.include?(1..5, 2..3))      # => false
```

```ruby error
p(Range.include?("a".., "b"))      # !> TypeError: Range.include?: cannot determine inclusion in beginless/endless ranges
```

## overlap?

`Range.overlap?(x, Range)`

2 つの Range が少なくとも 1 つの値を共有するとき true（Ruby の `overlap?`）。除外された終端は数えません（`1...5` と `5..8` は重なりません）。端の型は何でもよく、型の違う Range 同士は重なりません。

```ruby
p(Range.overlap?(1..5, 3..8))        # => true
p(Range.overlap?(1..5, 6..8))        # => false
p(Range.overlap?(1...5, 5..8))       # => false
p(Range.overlap?(1.., 100..200))     # => true
p(Range.overlap?(1.0..2.0, 1.5..3.0))  # => true
```

## size

`Range.size(x)`

Range に含まれる Integer の個数（Integer）。Integer の Range だけに使えます: String の Range は `type` の問題（`the Range's first value must be Integer, but is String`）、Float になりうる Range（`1..2.5`）も同様です。終端の無い Range は `RangeError`。始端が終端より大きい Range の size は 0 です。String の Range には `count` を使います。

```ruby
p(Range.size(1..5))      # => 5
p(Range.size(1...5))     # => 4
p(Range.size(5..1))      # => 0
```

```ruby error
p(Range.size(1..))       # !> RangeError: Range.size: cannot do this on an endless Range 1..
```

## count

`Range.count(x) [{ }]`

ブロック無しなら Range を辿って数えた値の個数（Integer）、ブロック付きならブロックが真を返した値の個数。Integer と String の Range に使えます。有限の Range が要ります（`RangeError`）。Ruby の `count(v)` と違って値を渡す形は無く、`include?` を使います。

```ruby
p(Range.count("a".."c"))                        # => 3
p(Range.count(1..5) { |i| Integer.odd?(i) })    # => 3
```

## each

`Range.each(x) { }`

各値を順にブロックへ渡し、Range を返します。Integer の Range は 1 ずつ、String の Range は `String#succ` で進みます（`"az".."bc"` は `"az"`、`"ba"`、`"bb"`、`"bc"`）。終端の無い Range は `break` するまで走り、`break v` なら `v` が結果です。ブロックの引数は 1 つ。Float の Range は `type` の問題です。

```ruby
r = Range.each(1..3) { |i| puts(i) }     # => 1
                                         # => 2
                                         # => 3
p(r)                                     # => 1..3
Range.each("a".."c") { |s| print(s) }    # => abc
puts("")
x = Range.each(1..) { |i| break i * 10 if i > 2 }
p(x)                                     # => 30
```

```ruby error
Range.each(1.0..2.0) { |f| p(f) }        # !> the Range's first value must be Integer|String, but is Float
```

## each_with_index

`Range.each_with_index(x) { }`

各値とその位置（0, 1, 2, ...）をブロックへ渡し、Range を返します。ブロックの引数は 2 つ。終端の無い Range には `break` が要ります。

```ruby
r = Range.each_with_index("a".."c") { |s, i| p([s, i]) }   # => ["a", 0]
                                                            # => ["b", 1]
                                                            # => ["c", 2]
p(r)                                                        # => "a".."c"
```

## each_entry

`Range.each_entry(x) { }`

`each` と同じです: Ruby の `Enumerable#each_entry` で、それに合わせて書かれたプログラムのために残してあります。Range を返します。

```ruby
p(Range.each_entry(1..3) { |i| puts(i) })    # => 1
                                             # => 2
                                             # => 3
                                             # => 1..3
```

## reverse_each

`Range.reverse_each(x) { }`

各値を終端から始端へ向かってブロックへ渡し、Range を返します。有限の Range が要ります（`RangeError`）。

```ruby
p(Range.reverse_each(1..3) { |i| puts(i) })  # => 3
                                             # => 2
                                             # => 1
                                             # => 1..3
```

## step

`Range.step(x, Integer) { }`

始端、始端 + 刻み、... と Range の中にある間ブロックへ渡し、Range を返します。Integer の Range だけに使えます（String や Float の Range は `type`）。終端の無い Range には `break` が要ります。負の刻みは下る Range を辿り（`10..1` に -3 で 10, 7, 4, 1）、上る Range では何も渡しません。刻み 0 は `ArgumentError`（`step can't be 0`）です。

```ruby
p(Range.step(1..10, 3) { |i| puts(i) })    # => 1
                                           # => 4
                                           # => 7
                                           # => 10
                                           # => 1..10
Range.step(1...9, 4) { |i| p(i) }          # => 1
                                           # => 5
Range.step(10..1, -3) { |i| p(i) }         # => 10
                                           # => 7
                                           # => 4
                                           # => 1
```

```ruby error
Range.step("a".."z", 2) { |s| p(s) }       # !> the Range's first value must be Integer, but is String
```

```ruby error
Range.step(1..5, 0) { |i| p(i) }           # !> ArgumentError: Range.step: step can't be 0
```

## each_slice

`Range.each_slice(x, Integer) { }`

値を n 個ずつの Array にしてブロックへ渡し（最後は足りなければ短い）、Range を返します。終端の無い Range には `break` が要ります。0 以下の大きさは `ArgumentError`。

```ruby
p(Range.each_slice(1..7, 3) { |a| p(a) })    # => [1, 2, 3]
                                             # => [4, 5, 6]
                                             # => [7]
                                             # => 1..7
```

## each_cons

`Range.each_cons(x, Integer) { }`

連続する n 個の値の窓を Array としてブロックへ渡し、Range を返します。値が n 個に足りなければブロックは呼ばれません。0 以下の大きさは `ArgumentError`。

```ruby
p(Range.each_cons(1..4, 2) { |a| p(a) })     # => [1, 2]
                                             # => [2, 3]
                                             # => [3, 4]
                                             # => 1..4
```

## each_with_object

`Range.each_with_object(x, Any) { }`

各値と渡したオブジェクトをブロックへ渡し、そのオブジェクトを返します。容器を埋めるのに使います。Ruby と同じく、ブロックが新しい値を返してもオブジェクトは変わりません（`Range.each_with_object(1..3, 0) { |i, acc| acc + i }` は 0 を返す。`reduce` を使う）。終端の無い Range には `break` が要ります。

```ruby
a = Range.each_with_object(1..3, Any[]) { |i, acc| Array.push(acc, i * i) }
p(a)                                         # => [1, 4, 9]
```

## cycle

`Range.cycle(x, Integer) { }`

Range を n 回繰り返して辿り、nil を返します。n が 0 以下なら何もしません。有限の Range が要ります（`RangeError`）。引数無しの Ruby の `cycle` と違い、回数は必須です。

```ruby
p(Range.cycle(1..2, 2) { |i| puts(i) })      # => 1
                                             # => 2
                                             # => 1
                                             # => 2
                                             # => nil
```

## to_a, entries

`Range.to_a(x)`

`Range.entries(x)`

すべての値を持つ新しい Array。Integer か String の Range（それ以外は `type`）で、有限なもの（`RangeError`）が要ります。Array の要素の型は端の型です。

```ruby
p(Range.to_a(1..5))          # => [1, 2, 3, 4, 5]
p(Range.to_a(1...5))         # => [1, 2, 3, 4]
p(Range.entries("a".."e"))   # => ["a", "b", "c", "d", "e"]
p(Range.to_a(5..1))          # => []
```

```ruby error
p(Range.to_a(1..))           # !> RangeError: Range.to_a: cannot do this on an endless Range 1..
```

## first

`Range.first(x, [Integer])`

個数無しなら Range の始端を、中身にかかわらず返します（`Range.first(5..1)` は 5、`Range.first(1...1)` は 1、`Range.first(1.0..2.0)` は 1.0）。型は `T | nil` で、算術の前の検査を `--strict` が求めます。始端の無い Range は nil を返すのではなく `RangeError`（`cannot get the first element of beginless range`）です。個数 n 付きなら先頭 n 個の値の新しい Array（Range が短ければそれだけ）。Range を辿るので Integer か String の Range が要ります（Float の Range は実行時に `TypeError`、`can't iterate from Float`）。終端の無い Range でも使えます。負の個数は `RangeError`（`negative array size (or size too big)`）。

```ruby
p(Range.first(1..5))         # => 1
p(Range.first(1..5, 2))      # => [1, 2]
p(Range.first(1..5, 10))     # => [1, 2, 3, 4, 5]
p(Range.first(1.., 3))       # => [1, 2, 3]
p(Range.first("a".."c", 2))  # => ["a", "b"]
```

```ruby error
p(Range.first(..5))          # !> RangeError: Range.first: cannot get the first element of beginless range
```

```ruby error
p(Range.first(1.0..2.0, 2))  # !> TypeError: Range.first: can't iterate from Float
```

## last

`Range.last(x, [Integer])`

個数無しなら書かれた終端を `Range.end` と同じく返します（なので Ruby と同じく `Range.last(1...5)` は 5）。個数 n 付きなら末尾 n 個の値の新しい Array で、除外された終端は入りません（`Range.last(1...5, 2)` は `[3, 4]`）。有限の Range が要ります（終端の無い Range は個数無しでも `RangeError`）。個数無しの結果は `T | nil`。負の個数は `RangeError`。

```ruby
p(Range.last(1..5))          # => 5
p(Range.last(1...5))         # => 5
p(Range.last(1..5, 2))       # => [4, 5]
p(Range.last(1...5, 2))      # => [3, 4]
p(Range.last("a".."c"))      # => "c"
```

```ruby error
p(Range.last(1..))           # !> RangeError: Range.last: cannot do this on an endless Range 1..
```

## take

`Range.take(x, Integer)`

先頭 n 個の値の新しい Array（足りなければ全部）。`first(r, n)` と同じです。終端の無い Range でも使えます。負の n は `ArgumentError`。

```ruby
p(Range.take(1..10, 3))      # => [1, 2, 3]
p(Range.take(1.., 3))        # => [1, 2, 3]
p(Range.take(1..3, 10))      # => [1, 2, 3]
```

## drop

`Range.drop(x, Integer)`

先頭 n 個を除いた残りの値の新しい Array（残りが無ければ空）。有限の Range が要ります（`RangeError`）。負の n は `ArgumentError`。

```ruby
p(Range.drop(1..5, 2))       # => [3, 4, 5]
p(Range.drop(1..5, 10))      # => []
```

## take_while

`Range.take_while(x) { }`

始端から、ブロックが初めて偽を返した値の直前までの新しい Array。ブロックがいずれ偽を返すなら、終端の無い Range でも使えます。

```ruby
p(Range.take_while(1..10) { |i| i < 4 })   # => [1, 2, 3]
p(Range.take_while(1..) { |i| i < 4 })     # => [1, 2, 3]
```

## drop_while

`Range.drop_while(x) { }`

ブロックが初めて偽を返した値から終端までの新しい Array。終端の無い Range は拒否されませんが、結果が終わらないので、この操作は戻ってきません。

```ruby
p(Range.drop_while(1..6) { |i| i < 4 })    # => [4, 5, 6]
```

## map, collect

`Range.map(x) { }`

`Range.collect(x) { }`

値ごとのブロックの結果を集めた新しい Array。有限の Integer か String の Range が要ります。Array の要素の型はブロックの結果の型です。

```ruby
n = 4
p(Range.map(1..n) { |i| i * i })                 # => [1, 4, 9, 16]
p(Range.collect("a".."c") { |s| String.upcase(s) })   # => ["A", "B", "C"]
```

```ruby error
p(Range.map(1..) { |i| i })                      # !> RangeError: Range.map: cannot do this on an endless Range 1..
```

## flat_map, collect_concat

`Range.flat_map(x) { }`

`Range.collect_concat(x) { }`

ブロックが返した Array（または Tuple）を 1 段つなげた新しい Array。ブロックは Array か Tuple を返さなければならず、他の値は実行時に `TypeError`（`the block must return an Array or a Tuple, got Integer`）です。有限の Range が要ります。

```ruby
p(Range.flat_map(1..3) { |i| Any[i, i] })      # => [1, 1, 2, 2, 3, 3]
p(Range.flat_map(1..2) { |i| [i, i * 10] })      # => [1, 10, 2, 20]
```

```ruby error
p(Range.flat_map(1..2) { |i| i })                # !> TypeError: Range.flat_map: the block must return an Array or a Tuple, got Integer
```

## select, filter, find_all

`Range.select(x) { }`

`Range.filter(x) { }`

`Range.find_all(x) { }`

ブロックが真を返した値の新しい Array。有限の Integer か String の Range が要ります。Array の要素の型は端の型です。

```ruby
p(Range.select(1..6) { |i| Integer.even?(i) })   # => [2, 4, 6]
p(Range.filter("a".."e") { |s| s > "c" })        # => ["d", "e"]
```

## reject

`Range.reject(x) { }`

ブロックが偽を返した値の新しい Array。`select` の補集合です。有限の Range が要ります。

```ruby
p(Range.reject(1..6) { |i| Integer.even?(i) })   # => [1, 3, 5]
```

## filter_map

`Range.filter_map(x) { }`

ブロックの結果のうち nil と false を除いた新しい Array（Ruby の `filter_map`）。検査器は要素の型から nil を外すので、この Array は nil 検査なしで使えます。有限の Range が要ります。

```ruby
p(Range.filter_map(1..6) { |i| Integer.even?(i) ? i * 10 : nil })   # => [20, 40, 60]
```

## partition

`Range.partition(x) { }`

2 つの Array の Tuple: ブロックが真を返した値たち、それから残り。有限の Range が要ります。

```ruby
evens, odds = Range.partition(1..6) { |i| Integer.even?(i) }
p(evens)                                         # => [2, 4, 6]
p(odds)                                          # => [1, 3, 5]
```

## group_by

`Range.group_by(x) { }`

ブロックの結果ごとに、その結果を与えた値の Array を対応づけた Hash（初出の順）。有限の Range が要ります。キーの型はブロックの結果の型、値の型は端の型の Array です（無いキーの `h[k]` は他の Hash と同じく nil）。

```ruby
h = Range.group_by(1..6) { |i| i % 3 }
p(h)                                             # => {1 => [1, 4], 2 => [2, 5], 0 => [3, 6]}
p(h[1])                                          # => [1, 4]
```

## chunk_while, slice_when

`Range.chunk_while(x) { }`

`Range.slice_when(x) { }`

値を連なりに切り分けた Array の Array。ブロックは隣り合う 2 つの値を受け取り、`chunk_while` はブロックが真の間同じ連なりに入れ、`slice_when` はブロックが真のところで新しい連なりを始めます。有限の Range が要ります。

```ruby
p(Range.chunk_while(1..5) { |a, b| b != 3 })         # => [[1, 2], [3, 4, 5]]
p(Range.slice_when(1..6) { |a, b| Integer.even?(b) })  # => [[1], [2, 3], [4, 5], [6]]
```

## slice_before, slice_after

`Range.slice_before(x) { }`

`Range.slice_after(x) { }`

ブロックが真を返した値の前（または後）で値を切り分けた Array の Array。有限の Range が要ります。

```ruby
p(Range.slice_before(1..6) { |i| Integer.even?(i) })  # => [[1], [2, 3], [4, 5], [6]]
p(Range.slice_after(1..6) { |i| Integer.even?(i) })   # => [[1, 2], [3, 4], [5, 6]]
```

## find, detect

`Range.find(x) { }`

`Range.detect(x) { }`

ブロックが初めて真を返した値。無ければ nil。結果は `T | nil` なので、使う前の検査を `--strict` が求めます。どれかの値がブロックを満たすなら終端の無い Range でも使えます。満たさなければ探索は終わりません。

```ruby
p(Range.find(1..10) { |i| i * i > 10 })      # => 4
p(Range.detect(1..10) { |i| i > 100 })       # => nil
p(Range.find(1..) { |i| i * i > 10 })        # => 4
s = Range.find("a".."e") { |c| c > "b" }
if s
  p(String.upcase(s))                        # => "C"
end
```

## find_index

`Range.find_index(x) { }`

ブロックが初めて真を返した値の位置（0, 1, 2, ...）。無ければ nil（`Integer | nil`）。Ruby の `find_index(v)` と違い、ブロックが必須で値を渡す形はありません。見つかるなら終端の無い Range でも使えます。

```ruby
p(Range.find_index(1..10) { |i| i * i > 10 })  # => 3
p(Range.find_index(1..10) { |i| i > 100 })     # => nil
```

## bsearch

`Range.bsearch(x) { }`

Integer の Range の二分探索（Ruby と同じ）: find-minimum モードでは、求める値とそれより上のすべての値でブロックが true を返すようにし、結果はそのような最小の値です。ブロックが一度も true にならなければ nil（`T | nil`）。終端の無い Range でも使えます。String の Range は実行時に `TypeError`（`can't do binary search for String`）。

```ruby
p(Range.bsearch(1..100) { |i| i * i >= 50 })   # => 8
p(Range.bsearch(1..100) { |i| i > 1000 })      # => nil
p(Range.bsearch(1..) { |i| i * i >= 50 })      # => 8
```

```ruby error
p(Range.bsearch("a".."z") { |s| s >= "m" })    # !> TypeError: Range.bsearch: can't do binary search for String
```

## all?, any?, none?, one?

`Range.all?(x) { }`

`Range.any?(x) { }`

`Range.none?(x) { }`

`Range.one?(x) { }`

ブロックがすべての値で真か、少なくとも 1 つで真か、どれでも偽か、ちょうど 1 つで真か。Ruby と違ってブロックは必須です（ブロック無しの `any?` やパターン引数はありません）。有限の Range が要ります（`RangeError`）。値の無い Range では `all?` と `none?` が true、`any?` と `one?` が false。

```ruby
p(Range.all?(1..5) { |i| i > 0 })    # => true
p(Range.any?(1..5) { |i| i > 4 })    # => true
p(Range.none?(1..5) { |i| i > 5 })   # => true
p(Range.one?(1..5) { |i| i == 3 })   # => true
p(Range.any?(5..1) { |i| true })     # => false
```

## reduce, inject

`Range.reduce(x, Any) { }`

`Range.inject(x, Any) { }`

値を畳み込みます: ブロックは累積値と次の値を受け取り、その結果が新しい累積値になります。結果は最後の累積値です。初期値は**必須**で（初期値無しの Ruby の `inject` は `wrong number of arguments` の問題）、結果の型は初期値の型とブロックの結果の型の和です。シンボル形（`reduce(:+)`）は無く、それには `sum` を使います。有限の Range が要ります。

```ruby
p(Range.reduce(1..5, 0) { |acc, i| acc + i })                   # => 15
p(Range.inject(1..5, 1) { |acc, i| acc * i })                   # => 120
p(Range.reduce(1..3, "") { |acc, i| acc + Integer.to_s(i) })    # => "123"
p(Range.reduce(5..1, 7) { |acc, i| acc + i })                   # => 7
```

```ruby error
p(Range.inject(1..5) { |acc, i| acc + i })   # !> wrong number of arguments for Range.inject (given 1, expected 2)
```

## sum

`Range.sum(x, [Integer|Float|Rational|Complex]) [{ }]`

値（ブロック付きならブロックの結果）の合計に初期値（省略時 0）を足したもの。Integer の Range だけ（String の Range は `type`）で、有限なもの（`RangeError`）が要ります。結果の型は初期値とブロックに従います: Integer の値に Integer の初期値なら Integer、Float の初期値なら Float。Ruby の `Range#sum` と同じく、Integer の Range に Rational の初期値を与えると Float になり（`Range.sum(1..3, 2r)` は 8.0）、Complex の初期値は実行時に `RangeError`（`can't convert 1+2i into Float`）です。数でない結果を返すブロックは `type` の問題です。

```ruby
p(Range.sum(1..100))                 # => 5050
p(Range.sum(1..10, 100))             # => 155
p(Range.sum(1..3) { |i| i * 2 })     # => 12
p(Range.sum(1..3, 0.5))              # => 6.5
p(Range.sum(1..3, 2r))               # => 8.0
p(Range.sum(1..0))                   # => 0
```

```ruby error
p(Range.sum("a".."c"))               # !> the Range's first value must be Integer, but is String
```

```ruby error
p(Range.sum(1..3, Complex(1, 2)))    # !> RangeError: Range.sum: can't convert 1+2i into Float
```

## min, max

`Range.min(x)`

`Range.max(x)`

最小と最大の値。値の無い Range（`5..1`）では nil で、型は `T | nil` です。`max` は除外された終端を数えません（`Range.max(1...5)` は 4）。有限の Range が要ります（`RangeError`）。終端を含む Float の Range はどちらも受け取ります（`Range.max(1.0..2.5)` は 2.5。Ruby と同じ）。終端を除く Float の Range の `max` は `TypeError`（`cannot exclude non Integer end value`。その `min` は使えます）。

```ruby
p(Range.min(1..5))           # => 1
p(Range.max(1...5))          # => 4
p(Range.max(5..1))           # => nil
p(Range.min("a".."c"))       # => "a"
p(Range.max(1.0..2.5))       # => 2.5
p(Range.min(1.0...2.5))      # => 1.0
```

```ruby error
x = Range.min(1..5)
p(x + 1)                     # !> the operands may be nil
```

```ruby error
p(Range.max(1.0...2.5))      # !> TypeError: Range.max: cannot exclude non Integer end value
```

## minmax

`Range.minmax(x)`

Tuple `[min, max]`。値の無い Range（`5..1`、`2.5..1.0`）では両方 nil で、これは外れの nil です（要素を確かめずに使うことは `--strict=3` でだけ報告）。有限の Range が要ります（`RangeError`）。`min`、`max` と同じく終端を含む Float の Range も受け取り（`Range.minmax(1.0..2.5)` は `[1.0, 2.5]`）、終端を除く Float の Range は `TypeError`（`cannot exclude non Integer end value`）です。

```ruby
lo, hi = Range.minmax(1..5)
p([lo, hi])                  # => [1, 5]
p(Range.minmax(5..1))        # => [nil, nil]
p(Range.minmax(1.0..2.5))    # => [1.0, 2.5]
p(Range.minmax("a".."c"))    # => ["a", "c"]
```

```ruby error
p(Range.minmax(1.0...2.5))   # !> TypeError: Range.minmax: cannot exclude non Integer end value
```

## min_by, max_by

`Range.min_by(x) { }`

`Range.max_by(x) { }`

ブロックの結果が最小（最大）になる値。値の無い Range では nil（`T | nil`）。有限の Range が要ります。

```ruby
p(Range.min_by(1..5) { |i| -i })               # => 5
p(Range.max_by("a".."e") { |s| String.ord(s) })  # => "e"
p(Range.min_by(5..1) { |i| i })                # => nil
```

## minmax_by

`Range.minmax_by(x) { }`

ブロックの結果が最小になる値と最大になる値の Tuple。値の無い Range では `[nil, nil]`（外れの nil で、`--strict=3` でだけ報告）。有限の Range が要ります。

```ruby
p(Range.minmax_by(1..5) { |i| -i })    # => [5, 1]
```

## sort

`Range.sort(x)`

値を昇順に並べた新しい Array。Range では `to_a` と同じです。有限の Integer か String の Range が要ります。

```ruby
p(Range.sort(1..3))          # => [1, 2, 3]
p(Range.sort(3..1))          # => []
```

## sort_by

`Range.sort_by(x) { }`

ブロックの結果の順に値を並べた新しい Array。有限の Range が要ります。

```ruby
p(Range.sort_by(1..5) { |i| -i })                    # => [5, 4, 3, 2, 1]
p(Range.sort_by("a".."c") { |s| -String.ord(s) })    # => ["c", "b", "a"]
```

## uniq

`Range.uniq(x)`

重複を除いた値の新しい Array。Range に重複は無いので `to_a` と同じです。有限の Integer か String の Range が要ります。

```ruby
p(Range.uniq(1..3))          # => [1, 2, 3]
```

## compact

`Range.compact(x)`

nil を除いた値の新しい Array。Range に nil は無いので `to_a` と同じです。有限の Integer か String の Range が要ります。

```ruby
p(Range.compact(1..3))       # => [1, 2, 3]
```

## tally

`Range.tally(x)`

各値をその出現回数に対応づけた Hash。Range では常に 1 です。有限の Integer か String の Range が要ります。

```ruby
p(Range.tally("a".."c"))     # => {"a" => 1, "b" => 1, "c" => 1}
```

## to_set

`Range.to_set(x)`

値の新しい Set。有限の Integer か String の Range が要ります。

```ruby
p(Range.to_set(1..3))        # => Set[1, 2, 3]
```

## zip

`Range.zip(x, *Array)`

Tuple の新しい Array: i 番目の Tuple は Range の i 番目の値と、渡した各 Array の i 番目の要素を持ちます。短い Array のところは nil です（Tuple の型にそう出ます）。Array を渡さなければ各 Tuple は値 1 つです。有限の Integer か String の Range が要ります。

```ruby
p(Range.zip(1..3, Any["a", "b", "c"]))     # => [[1, "a"], [2, "b"], [3, "c"]]
p(Range.zip(1..3, Any[10, 20]))            # => [[1, 10], [2, 20], [3, nil]]
p(Range.zip(1..2))                           # => [[1], [2]]
```

# Hash

Hash はキーから値への対応で、挿入順を保ちます。Ruby の `{"a" => 1}` のようなリテラルはなく、`Hash.of("a" => 1, b: 2)`、`Hash.new`、`Hash.new(default)` で構築します（[値と型](../03-values.md)）。**`{k: v}` は Record であって Hash ではありません**（`{}` も空の Record で、静的に拒否されます。[Record](Record.md)）。`Hash.of(name: v)` と書いたキーは Symbol です。

キーに使えるのは Integer、Float、String、Symbol、true、false、nil、Time と、それらだけからなる Tuple、Record、Array、Hash、Set、クラスのインスタンスです。Regexp、Range、独自の等価性（`==` や `Comparable`）を定義したクラスの値はキーにできず、実行時に `TypeError` です。Tuple と Record のキーは格納時に複製されるので、元の値を後で書き換えてもキーは変わりません（Array などのキーは Ruby と同じく、書き換えると見つからなくなります）。`"a"` と `:a`、`1` と `1.0` は別のキーです。

`h[k]` は見つからないと nil（`Hash.new(default)` で作った Hash なら default）を返します。この nil をそのまま使うことは `--strict=3` でだけ `index-nil` として報告されます（level 2 は報告しません）。見つからないことを例外にしたいときは `Hash.fetch` を使います。`Hash.dig`、`Hash.min_by`、`Hash.max_by` の nil も外れの nil です（level 3）。`Hash.delete`、`Hash.key`、`Hash.first`、`Hash.shift`、`Hash.find` などの nil は level 2 で報告されます。

ブロックを取る操作は、各要素を `[key, value]` の Tuple 1 つとして渡します。`|k, v|` と書けば分解され、`|kv|` なら Tuple のまま受け取ります。`each_with_object` は `|(k, v), memo|`、`reduce` は `|acc, (k, v)|` と書きます。繰り返しの順序は挿入順です。`to_a`、`sort_by`、`take`、`first` などが返す組も `[k, v]` の Tuple です。

検査器は Hash に、作られた場所ごとにキーの型と値の型を 1 つずつ与えます。`Hash.store` や `[]=` で別の型を入れると、その Hash の値の型は和になります（`Hash.of("a" => 1)` に `"x"` を入れると値は `Integer | String` で、`fetch` した値の `+ 1` は `type` の問題）。`transform_keys!`、`transform_values!` など要素の型を変える in-place 操作も同じです（下記）。

Hash に使える演算子は `==`、`!=` と添字 `h[k]`、`h[k] = v` です。`Hash.==(x, y)` などは演算子の関数形です（[演算子と添字](../05-operators.md)）。

## of

`Hash.of(*Any)`

`Hash.of(k => v, ...)` は新しい Hash を作ります。引数は `key => value` の組だけで（`Hash.of(name: v)` のラベル形はキーが Symbol）、組以外（`Hash.of(1)`、`Hash.of({x: 1})`）は静的なエラーです。`Hash.new` は空の Hash。同じキーを 2 度書くと後の値が残ります。キーにできない値は実行時に `TypeError`。

```ruby
h = Hash.of("a" => 1, b: 2)
p(h)                               # => {"a" => 1, b: 2}
p(Hash.new)                          # => {}
p(Hash.of(1 => 2, 1 => 3))            # => {1 => 3}
p(Hash.of([1, 2] => "t", nil => "n"))  # => {[1, 2] => "t", nil => "n"}
```

```ruby error
p(Hash.of(1))                         # !> Hash.of takes `key => value` pairs, like `Hash.of("a" => 1)`
```

## Hash[]

`Hash[*Any]`

Hash の Array を作ります。どの T でも `T[...]` が T の Array を作るのと同じで、各要素は Hash でなければならず、書き込みのたびに検査されます。Hash そのものは `Hash.of(k => v, ...)` か `Hash.new` で作ります。

```ruby
hs = Hash[Hash.of(a: 1), Hash.new]
p(hs)                              # => [{a: 1}, {}]
```

## new

`Hash.new([Any])`

空の Hash を作ります。`Hash.new(default)` は見つからないキーに対して `h[k]` が default を返す Hash です（Ruby と同じ）。default はそのオブジェクト 1 つを共有するので、`Hash.new(Any[])` の Array を `h["x"]` 経由で変更するとすべてのキーで見えますし、Hash 自体には何も格納されません。Ruby のブロック形 `Hash.new { |h, k| ... }` はありません（静的なエラー）。`Hash.fetch` は default を見ません。

```ruby
counts = Hash.new(0)
counts["x"] += 1
counts["x"] += 1
p(counts)                          # => {"x" => 2}
p(counts["none"])                  # => 0
p(Hash.new["none"])                # => nil
d = Hash.new(Any[])
Array.push(d["a"], 1)
p(d["b"])                          # => [1]
p(d)                               # => {}
```

```ruby error
h = Hash.new { |hh, k| 0 }         # !> Hash.new does not take a block
```

## default, set_default

`Hash.default(x)`

`Hash.set_default(x, Any)`

`default` は見つからないキーに `h[k]` が返す値（`Hash.new(default)` の default。無ければ nil）。`set_default(h, v)` はそれを `v` に変えて `v` を返します（Ruby の `h.default = v`）。検査器は `h[k]` の型に default の型を加えます。

```ruby
h = Hash.new(0)
p(Hash.default(h))                 # => 0
p(Hash.default(Hash.new))            # => nil
Hash.set_default(h, 5)
p(h["q"])                          # => 5
```

## []

`Hash.[](x, Any)`

`h[k]` の関数形。キー `k` の値を返します。無ければ default（通常 nil）。この nil は `--strict=3` でだけ `index-nil` として報告されます。キーの型は何でもよく、どんな値でも静的な問題にはなりません。`Hash.new(default)` の Hash では default の型が結果に加わるので、`Hash.new(0)` の `h[k] + 1` は level 3 でも通ります。

```ruby
h = Hash.of("a" => 1, [1, 2] => "t")
p(h["a"])                          # => 1
p(h[[1, 2]])                       # => "t"
p(h["zz"])                         # => nil
p(Hash.[](h, "a"))                 # => 1
```

## []=, store

`Hash.[]=(x, Any, Any)`

`Hash.store(x, Any, Any)`

`h[k] = v` とその関数形。キー `k` に値 `v` を結び付け、`v` を返します。新しいキーは末尾に加わり、既存のキーは値だけ変わって位置は動きません。キーにできない値は `TypeError`。検査器はこの Hash のキーの型・値の型に `k`、`v` の型を加えます。

```ruby
h = Hash.of("a" => 1)
h["b"] = 2
p(Hash.store(h, "a", 10))          # => 10
p(h)                               # => {"a" => 10, "b" => 2}
```

```ruby error
Hash.store(Hash.new, /x/, 1)         # !> TypeError: Hash.store: Regexp cannot be a Hash key or Set element
```

## fetch

`Hash.fetch(x, Any, [Any])`

キー `k` の値を返します。無いときは、第 3 引数 `default` があればそれを返し、無ければ `KeyError`（Ruby と同じ。ブロック形はありません）。`Hash.new(default)` の default は使いません。結果の型は値の型と `default` の型の和で、値が nil でなければ nil になりえないので、`h[k]` の代わりに使えば `--strict=3` の `index-nil` も出ません。

```ruby
h = Hash.of("a" => 1)
p(Hash.fetch(h, "a"))              # => 1
p(Hash.fetch(h, "zz", 0))          # => 0
p(Hash.fetch(h, "a") + 1)          # => 2
```

```ruby error
p(Hash.fetch(Hash.of("a" => 1), "b")) # !> KeyError: Hash.fetch: key not found: "b"
```

## dig

`Hash.dig(x, Any, *Any)`

Ruby の `dig` と同じく、キーを順に使って入れ子の容器を掘り進みます: `dig(h, k)` は `h[k]` で、以降のキーはそこまでに見つかった値への添字です（Hash ならキー、Array と Tuple なら位置）。結果は辿り着いた値で、途中でキーが見つからなければそこで nil です（`Hash.new(default)` で作った Hash での外れは `h[k]` と同じく default で、検査器も default の型を結果に加えます）。この nil は `h[k]` と同じ外れの nil で、そのまま使うことは `--strict=3` でだけ `index-nil` として報告されます（level 2 は報告しません）。検査器はキーを型の上で辿り、Hash・Array・Tuple でない値（Integer、String、Record）にキーを当てるのは静的に `type` の問題です（`the value must be Array|Hash|Tuple, but is Integer`）。辿り着いた容器に合わない種類のキー（Array に String）は実行時に `TypeError`（`an index into Array must be Integer, got String`）。

```ruby
h = Hash.of("a" => Hash.of("b" => Any[10, 20]))
p(Hash.dig(h, "a", "b", 1))        # => 20
p(Hash.dig(h, "a", "zz", 1))       # => nil
p(Hash.dig(h, "zz"))               # => nil
t = Hash.of("t" => [1, "x"])
p(Hash.dig(t, "t", 1))             # => "x"
p(Hash.dig(t, "t", 5))             # => nil
p(Hash.dig(Hash.new(0), "q") + 1)  # => 1
x = Hash.dig(h, "a", "b", 0)
if x
  p(x + 1)                         # => 11
end
```

```ruby error
p(Hash.dig(Hash.of("a" => 1), "a", "b"))   # !> Hash.dig: the value must be Array|Hash|Tuple, but is Integer
```

## fetch_values

`Hash.fetch_values(x, *Any)`

列挙したキーの値を順に並べた Array を返します。無いキーがあれば `KeyError`（default は見ません）。要素の型は値の型で、nil にはなりません。

```ruby
h = Hash.of("a" => 1, "b" => 2)
p(Hash.fetch_values(h, "b", "a"))  # => [2, 1]
```

```ruby error
p(Hash.fetch_values(Hash.of("a" => 1), "a", "zz"))   # !> KeyError: Hash.fetch_values: key not found: "zz"
```

## values_at

`Hash.values_at(x, *Any)`

列挙したキーの値を順に並べた Array を返します。無いキーの位置は default（通常 nil）です。要素の型は `値 | nil` なので、要素をそのまま使うと level 2 で報告されます。

```ruby
h = Hash.of("a" => 1, "b" => 2)
p(Hash.values_at(h, "a", "zz"))    # => [1, nil]
p(Hash.values_at(Hash.new(9), "x"))   # => [9]
```

## key?, has_key?, include?, member?

`Hash.key?(x, Any)`

`Hash.has_key?(x, Any)`

`Hash.include?(x, Any)`

`Hash.member?(x, Any)`

キー `k` があれば true。値が nil でも true です（`h[k]` が nil でも区別できます）。4 つは同じ操作です。

```ruby
h = Hash.of("a" => nil)
p(Hash.key?(h, "a"))               # => true
p(Hash.include?(h, "b"))           # => false
p(h["a"])                          # => nil
```

## value?, has_value?

`Hash.value?(x, Any)`

`Hash.has_value?(x, Any)`

`v` と `==` で等しい値があれば true。

```ruby
h = Hash.of("a" => 1, "b" => 2)
p(Hash.value?(h, 2))               # => true
p(Hash.has_value?(h, 3))           # => false
```

## key

`Hash.key(x, Any)`

値が `v` と等しい最初のキーを返します。無ければ nil（level 2 で報告）。

```ruby
h = Hash.of("a" => 1, "b" => 2, "c" => 2)
p(Hash.key(h, 2))                  # => "b"
p(Hash.key(h, 9))                  # => nil
```

## assoc, rassoc

`Hash.assoc(x, Any)`

`Hash.rassoc(x, Any)`

`assoc(h, k)` はキー `k` の組 `[k, v]`、`rassoc(h, v)` は値が `v` の最初の組 `[k, v]` を Tuple で返します。無ければ nil（level 2 で報告）。

```ruby
h = Hash.of("a" => 1, "b" => 2)
p(Hash.assoc(h, "a"))              # => ["a", 1]
p(Hash.rassoc(h, 2))               # => ["b", 2]
p(Hash.assoc(h, "zz"))             # => nil
```

## length, size

`Hash.length(x)`

`Hash.size(x)`

組の個数（Integer）。

```ruby
p(Hash.size(Hash.of("a" => 1, "b" => 2)))   # => 2
p(Hash.length(Hash.new))                   # => 0
```

## empty?

`Hash.empty?(x)`

組が 1 つも無ければ true。

```ruby
p(Hash.empty?(Hash.new))             # => true
p(Hash.empty?(Hash.new(0)))        # => true
p(Hash.empty?(Hash.of("a" => 1)))     # => false
```

## count

`Hash.count(x) [{ }]`

ブロックなしなら組の個数（`size` と同じ）、ブロックがあれば `[k, v]` を受けて真を返した組の個数（Integer）。

```ruby
h = Hash.of("a" => 1, "b" => 2, "c" => 3)
p(Hash.count(h))                   # => 3
p(Hash.count(h) { |k, v| v >= 2 })   # => 2
```

## keys

`Hash.keys(x)`

キーを挿入順に並べた新しい Array。要素の型はキーの型です。型付き Array ではないので、他の型の値も push できます。

```ruby
h = Hash.of("b" => 2, "a" => 1)
p(Hash.keys(h))                    # => ["b", "a"]
p(Hash.keys(Hash.new))               # => []
```

## values

`Hash.values(x)`

値を挿入順に並べた新しい Array。要素の型は値の型です。

```ruby
h = Hash.of("b" => 2, "a" => 1)
p(Hash.values(h))                  # => [2, 1]
```

## to_a

`Hash.to_a(x)`

組を `[k, v]` の Tuple にして挿入順に並べた新しい Array。Ruby の `to_a` が返す内側の Array は、Sake では Tuple です。

```ruby
h = Hash.of(1 => "x", 2 => "y")
p(Hash.to_a(h))                    # => [[1, "x"], [2, "y"]]
Array.each(Hash.to_a(h)) { |k, v| p(k) }   # => 1
                                           # => 2
```

## flatten

`Hash.flatten(x)`

キーと値を交互に並べた新しい Array `[k1, v1, k2, v2, ...]`。Ruby の `flatten` の深さ 1 と同じで、値の Array や Tuple は開きません（深さの引数はありません）。要素の型はキーの型と値の型の和です。

```ruby
p(Hash.flatten(Hash.of(1 => "x", 2 => "y")))        # => [1, "x", 2, "y"]
p(Hash.flatten(Hash.of("a" => Any[1, 2])))        # => ["a", [1, 2]]
```

## to_h

`Hash.to_h(x)`

その Hash 自身を返します（Ruby の `Hash#to_h` と同じで、複製ではありません）。ブロック形はありません。複製には `Hash.dup`。

```ruby
h = Hash.of("a" => 1)
p(Hash.to_h(h))                    # => {"a" => 1}
p(Kernel.equal?(Hash.to_h(h), h))  # => true
```

## dup

`Hash.dup(x)`

同じ組を持つ新しい Hash（浅い複製。キーと値のオブジェクトは共有）。default も引き継ぎます。一方への `store` や `delete` は他方に影響しません。

```ruby
h = Hash.new(0)
Hash.store(h, "a", 1)
h2 = Hash.dup(h)
Hash.store(h2, "b", 2)
p(h)                               # => {"a" => 1}
p(h2)                              # => {"a" => 1, "b" => 2}
p(h2["zz"])                        # => 0
```

## first

`Hash.first(x)`

最初に挿入された組 `[k, v]` を Tuple で返します。空なら nil（level 2 で報告）。Ruby の `first(n)` の形はなく、先頭 n 組は `Hash.take`。

```ruby
p(Hash.first(Hash.of("a" => 1, "b" => 2)))   # => ["a", 1]
p(Hash.first(Hash.new))                     # => nil
```

## take, drop

`Hash.take(x, Integer)`

`Hash.drop(x, Integer)`

`take(h, n)` は先頭 n 組、`drop(h, n)` は先頭 n 組を除いた残りを、`[k, v]` の Tuple の Array で返します。Hash は変わりません。n が組の数より大きくても構いません。負の n は `ArgumentError`。

```ruby
h = Hash.of("a" => 1, "b" => 2, "c" => 3)
p(Hash.take(h, 2))                 # => [["a", 1], ["b", 2]]
p(Hash.drop(h, 2))                 # => [["c", 3]]
p(Hash.drop(h, 5))                 # => []
```

```ruby error
p(Hash.take(Hash.of("a" => 1), -1))   # !> ArgumentError: Hash.take: attempt to take negative size
```

## each, each_pair

`Hash.each(x) { }`

`Hash.each_pair(x) { }`

各組についてブロックを挿入順に呼び、Hash 自身を返します。ブロックは `[k, v]` の Tuple を受け取ります（`|k, v|` で分解）。ブロックは必須です（ブロック無しで Enumerator を返す Ruby の形はありません）。

```ruby
h = Hash.of("a" => 1, "b" => 2)
Hash.each(h) { |k, v| p(k + Integer.to_s(v)) }   # => "a1"
                                                 # => "b2"
Hash.each_pair(h) { |kv| p(kv) }                 # => ["a", 1]
                                                 # => ["b", 2]
r = Hash.each(h) { |k, v| nil }
p(Kernel.equal?(r, h))                           # => true
```

## each_key

`Hash.each_key(x) { }`

各キーについてブロックを呼び、Hash 自身を返します。ブロックはキーだけを受け取ります。

```ruby
Hash.each_key(Hash.of("a" => 1, "b" => 2)) { |k| p(k) }   # => "a"
                                                       # => "b"
```

## each_value

`Hash.each_value(x) { }`

各値についてブロックを呼び、Hash 自身を返します。ブロックは値だけを受け取ります。

```ruby
Hash.each_value(Hash.of("a" => 1, "b" => 2)) { |v| p(v * 10) }   # => 10
                                                              # => 20
```

## each_with_object

`Hash.each_with_object(x, Any) { }`

`memo` を引き回しながら各組についてブロックを呼び、最後に `memo` を返します。ブロックは `[k, v]` の Tuple と `memo` の 2 つを受け取るので、`|(k, v), memo|` と書きます。結果の型は `memo` の型です。

```ruby
h = Hash.of("a" => 1, "b" => 2)
ks = Hash.each_with_object(h, Any[]) { |(k, v), acc| Array.push(acc, k) }
p(ks)                              # => ["a", "b"]
```

## map

`Hash.map(x) { }`

各組について `[k, v]` を渡してブロックを呼び、その結果を並べた新しい Array を返します。Ruby と同じく結果は Hash ではなく Array です（Hash を得るなら `transform_values` や `to_h`）。

```ruby
h = Hash.of("a" => 1, "b" => 2)
p(Hash.map(h) { |k, v| k + Integer.to_s(v) })   # => ["a1", "b2"]
p(Hash.map(h) { |kv| kv })                      # => [["a", 1], ["b", 2]]
```

## flat_map

`Hash.flat_map(x) { }`

各組についてブロックを呼び、ブロックが返した Array をすべてつなげた新しい Array を返します。ブロックは **Array か Tuple** を返さなければならず（Tuple の要素も Array と同じくつなげられます）、スカラーを返すと実行時に `TypeError`（`the block must return an Array or a Tuple, got Integer`。Ruby は Array 以外をそのまま並べます）。

```ruby
h = Hash.of("a" => 1, "b" => 2)
p(Hash.flat_map(h) { |k, v| Any[k, v] })   # => ["a", 1, "b", 2]
p(Hash.flat_map(h) { |k, v| [k, v] })        # => ["a", 1, "b", 2]
```

```ruby error
Hash.flat_map(Hash.of("a" => 1)) { |k, v| v }   # !> TypeError: Hash.flat_map: the block must return an Array or a Tuple, got Integer
```

## filter_map

`Hash.filter_map(x) { }`

各組についてブロックを呼び、nil と false 以外の結果を並べた新しい Array を返します。

```ruby
h = Hash.of("a" => 1, "b" => 2, "c" => 3)
p(Hash.filter_map(h) { |k, v| v > 1 ? k : nil })   # => ["b", "c"]
```

## select, filter

`Hash.select(x) { }`

`Hash.filter(x) { }`

ブロックが真を返した組だけを持つ新しい Hash を返します（Ruby と同じく結果は Hash）。元の Hash は変わりません。キー・値の型は元と同じです。

```ruby
h = Hash.of("a" => 1, "b" => 2, "c" => 3)
p(Hash.select(h) { |k, v| v > 1 })   # => {"b" => 2, "c" => 3}
p(Hash.filter(h) { |k, v| k == "a" })   # => {"a" => 1}
p(h)                                 # => {"a" => 1, "b" => 2, "c" => 3}
```

## reject

`Hash.reject(x) { }`

ブロックが真を返した組を除いた新しい Hash を返します。元の Hash は変わりません。

```ruby
h = Hash.of("a" => 1, "b" => 2, "c" => 3)
p(Hash.reject(h) { |k, v| v > 1 })   # => {"a" => 1}
```

## partition

`Hash.partition(x) { }`

ブロックが真を返した組と偽を返した組を、それぞれ `[k, v]` の Tuple の Array にして、2 要素の Tuple `[真の組, 偽の組]` で返します。多重代入で受けます。

```ruby
h = Hash.of("a" => 1, "b" => 2, "c" => 3)
odd, even = Hash.partition(h) { |k, v| Integer.odd?(v) }
p(odd)                             # => [["a", 1], ["c", 3]]
p(even)                            # => [["b", 2]]
```

## group_by

`Hash.group_by(x) { }`

各組についてブロックを呼び、その結果をキー、同じ結果になった組 `[k, v]` の Tuple の Array を値とする新しい Hash を返します。ブロックの結果はキーにできる値でなければなりません。

```ruby
h = Hash.of("a" => 1, "b" => 2, "c" => 3)
g = Hash.group_by(h) { |k, v| v % 2 }
p(g)                               # => {1 => [["a", 1], ["c", 3]], 0 => [["b", 2]]}
p(Hash.fetch(g, 0))                # => [["b", 2]]
```

## find, detect

`Hash.find(x) { }`

`Hash.detect(x) { }`

ブロックが最初に真を返した組 `[k, v]` を Tuple で返します。無ければ nil で、level 2 では nil のまま多重代入や添字に使うと報告されるので、`if` で確かめます。

```ruby
h = Hash.of("a" => 1, "b" => 2)
kv = Hash.find(h) { |k, v| v == 2 }
if kv
  k, v = kv
  p(k)                             # => "b"
end
p(Hash.detect(h) { |k, v| v == 9 })   # => nil
```

```ruby error
kv = Hash.find(Hash.of("a" => 1)) { |k, v| v == 1 }
k, v = kv                          # !> multiple assignment: argument 1 may be nil
```

## min_by, max_by

`Hash.min_by(x) { }`

`Hash.max_by(x) { }`

ブロックの結果が最小・最大になる組 `[k, v]` を Tuple で返します。空なら nil で、これは外れの nil です（`Array.min_by` と同じく、そのまま使うことは `--strict=3` でだけ報告）。ブロックの結果同士は比べられなければなりません: 比べられない型（Integer と String）が結果の型に混ざるブロックは静的に `type` の問題として退けられ、nil になりうる結果は `nil` の問題です。検査器に見えないとき（`Float.NAN`）は実行時に `ArgumentError`。

```ruby
h = Hash.of("a" => 3, "b" => 1, "c" => 2)
p(Hash.min_by(h) { |k, v| v })     # => ["b", 1]
p(Hash.max_by(h) { |k, v| v })     # => ["a", 3]
p(Hash.max_by(Hash.new) { |k, v| v })   # => nil
```

```ruby error
Hash.min_by(Hash.of("a" => 1, "b" => "x")) { |k, v| v }   # !> Hash.min_by: elements compared in order may be (Integer, String), which cannot be compared
```

## sort_by

`Hash.sort_by(x) { }`

ブロックの結果の昇順に組を並べ、`[k, v]` の Tuple の Array で返します（Ruby と同じく Hash ではなく Array）。ブロックの結果同士は比べられなければならず、比べられない型が結果の型に混ざると `min_by` と同じく静的に退けられます（`type`）。降順にはブロックで符号を反転するか `Array.reverse` を使います。Tuple を返せば辞書順です（[Tuple](Tuple.md)）。

```ruby
h = Hash.of("a" => 3, "b" => 1, "c" => 2)
p(Hash.sort_by(h) { |k, v| v })    # => [["b", 1], ["c", 2], ["a", 3]]
p(Hash.sort_by(h) { |k, v| -v })   # => [["a", 3], ["c", 2], ["b", 1]]
```

```ruby error
Hash.sort_by(Hash.of("a" => 1, "b" => "x")) { |k, v| v }   # !> Hash.sort_by: elements compared in order may be (Integer, String), which cannot be compared
```

## any?, all?, none?

`Hash.any?(x) { }`

`Hash.all?(x) { }`

`Hash.none?(x) { }`

ブロックが真を返す組が 1 つでもあるか（`any?`）、すべての組で真か（`all?`）、1 つも無いか（`none?`）。ブロックは必須です（Ruby のブロック無しの形はなく、静的なエラー。空かどうかは `empty?`）。空の Hash では `any?` は false、`all?` と `none?` は true。

```ruby
h = Hash.of("a" => 1, "b" => 2)
p(Hash.any?(h) { |k, v| v > 1 })   # => true
p(Hash.all?(h) { |k, v| v > 1 })   # => false
p(Hash.none?(h) { |k, v| v > 5 })  # => true
```

```ruby error
p(Hash.any?(Hash.of("a" => 1)))       # !> Hash.any? requires a block
```

## one?

`Hash.one?(x) { }`

ブロックが真を返す組がちょうど 1 つなら true。ブロックは必須です。

```ruby
h = Hash.of("a" => 1, "b" => 2)
p(Hash.one?(h) { |k, v| v == 2 })  # => true
p(Hash.one?(h) { |k, v| v > 0 })   # => false
```

## sum

`Hash.sum(x, [Integer|Float|Rational|Complex]) { }`

各組についてブロックを呼び、その結果を `init`（省略時 0）に足し合わせます。ブロックは必須で（Ruby のブロック無しの形はありません）、`init` は数値に限ります（String を渡すのは静的に `type` の問題。文字列の連結は `reduce`）。数でない結果を返すブロックは実行時に `TypeError`（`String can't be coerced into Integer`）。結果の型は `init` とブロックの結果の数値型から決まります。

```ruby
h = Hash.of("a" => 1, "b" => 2)
p(Hash.sum(h) { |k, v| v })        # => 3
p(Hash.sum(h, 0.5) { |k, v| v })   # => 3.5
p(Hash.sum(Hash.new) { |k, v| 1 })   # => 0
```

```ruby error
Hash.sum(Hash.of("a" => "x"), "") { |k, v| v }   # !> argument 2 must be Integer|Float|Rational|Complex, but is String
```

## reduce, inject

`Hash.reduce(x, Any) { }`

`Hash.inject(x, Any) { }`

初期値 `init` から始めて、各組について `|acc, (k, v)|` でブロックを呼び、その結果を次の `acc` にして、最後の結果を返します。初期値は必須です（Ruby の省略形はありません）。結果の型は `init` とブロックの結果の型の和です。

```ruby
h = Hash.of("a" => 1, "b" => 2)
p(Hash.reduce(h, 0) { |acc, (k, v)| acc + v })    # => 3
p(Hash.inject(h, "") { |acc, (k, v)| acc + k })   # => "ab"
```

## transform_values

`Hash.transform_values(x) { }`

各値にブロックを適用した結果を値とする新しい Hash を返します。ブロックは値だけを受け取ります。キーはそのまま、元の Hash は変わりません。結果の値の型はブロックの結果の型なので、型を変える変換はこちらを使います（in-place の `transform_values!` と違って元の型と和になりません）。

```ruby
h = Hash.of("a" => 1, "b" => 2)
p(Hash.transform_values(h) { |v| Integer.to_s(v) })   # => {"a" => "1", "b" => "2"}
p(h)                                                 # => {"a" => 1, "b" => 2}
```

## transform_keys

`Hash.transform_keys(x) { }`

各キーにブロックを適用した結果をキーとする新しい Hash を返します。ブロックはキーだけを受け取り、その結果はキーにできる値でなければなりません（`TypeError`）。2 つのキーが同じ結果になったときは後の組の値が残ります。元の Hash は変わりません。Ruby の Hash 引数の形（`transform_keys(a: :b)`）はありません。

```ruby
h = Hash.of("a" => 1, "b" => 2)
p(Hash.transform_keys(h) { |k| String.to_sym(k) })   # => {a: 1, b: 2}
p(Hash.transform_keys(Hash.of("a" => 1, "A" => 2)) { |k| String.downcase(k) })   # => {"a" => 2}
```

## transform_values!

`Hash.transform_values!(x) { }`

各値をブロックの結果に置き換え、Hash 自身を返します。検査器は Hash に 1 つの値の型を与えるので、型を変える変換（Integer から String）をするとその Hash の値の型は `Integer | String` の和になり、以後どちらか片方にしか合わない操作が `type`（partial）として報告されます。型を変えるなら新しい Hash を作る `transform_values` を使います。

```ruby
h = Hash.of("a" => 1, "b" => 2)
r = Hash.transform_values!(h) { |v| v * 10 }
p(h)                               # => {"a" => 10, "b" => 20}
p(Kernel.equal?(r, h))             # => true
```

```ruby error
h = Hash.of("a" => 1)
Hash.transform_values!(h) { |v| Integer.to_s(v) }   # !> argument 1 must be Integer, but can be String
```

## transform_keys!

`Hash.transform_keys!(x) { }`

各キーをブロックの結果に置き換え、Hash 自身を返します。結果はキーにできる値でなければなりません（`TypeError`）。`transform_values!` と同じく、型を変える変換はキーの型を和にするので、`Array.each(Hash.keys(h))` などで片方の型の操作を使うと `type` の問題です。型を変えるなら `transform_keys`。

```ruby
h = Hash.of("a" => 1, "b" => 2)
Hash.transform_keys!(h) { |k| String.upcase(k) }
p(h)                               # => {"A" => 1, "B" => 2}
```

```ruby error
h = Hash.of("a" => 1)
Hash.transform_keys!(h) { |k| String.to_sym(k) }   # !> argument 1 must be String, but can be Symbol
```

## merge

`Hash.merge(x, Hash)`

2 つの Hash の組を合わせた新しい Hash を返します。同じキーは第 2 引数の値が勝ちます。どちらも変わりません。第 2 引数は Hash でなければならず、Record（`{a: 2}`）を渡すのは静的に `type` の問題です。Ruby のブロック形（衝突時の値を決める）はありません。結果のキー・値の型は両方の和です。

```ruby
a = Hash.of("a" => 1, "b" => 2)
b = Hash.of("b" => 20, "c" => 3)
p(Hash.merge(a, b))                # => {"a" => 1, "b" => 20, "c" => 3}
p(a)                               # => {"a" => 1, "b" => 2}
```

```ruby error
p(Hash.merge(Hash.of("a" => 1), {a: 2}))   # !> Hash.merge: argument 2 must be Hash, but is {a: Integer}
```

## merge!, update

`Hash.merge!(x, Hash)`

`Hash.update(x, Hash)`

第 2 引数の組を第 1 引数の Hash に書き込み（同じキーは上書き）、第 1 引数自身を返します。検査器は第 1 引数のキー・値の型に第 2 引数の型を加えます。ブロック形はありません。

```ruby
h = Hash.of("a" => 1)
Hash.merge!(h, Hash.of("b" => 2))
p(Hash.update(h, Hash.of("a" => 10))) # => {"a" => 10, "b" => 2}
p(h)                               # => {"a" => 10, "b" => 2}
```

## replace

`Hash.replace(x, Hash)`

第 1 引数の中身をすべて第 2 引数の組に置き換え、第 1 引数自身を返します。

```ruby
h = Hash.of("a" => 1, "b" => 2)
p(Hash.replace(h, Hash.of("z" => 26)))   # => {"z" => 26}
p(h)                                  # => {"z" => 26}
```

## compact

`Hash.compact(x)`

値が nil の組を除いた新しい Hash を返します。結果の値の型から nil が取れます。

```ruby
h = Hash.of("a" => 1, "b" => nil)
p(Hash.compact(h))                 # => {"a" => 1}
p(h)                               # => {"a" => 1, "b" => nil}
```

## compact!

`Hash.compact!(x)`

値が nil の組をその場で取り除き、Hash 自身を返します。1 つも取り除かなかったときは nil（Ruby と同じ）で、戻り値をそのまま使うと level 2 で報告されます。

```ruby
h = Hash.of("a" => 1, "b" => nil)
p(Hash.compact!(h))                # => {"a" => 1}
p(Hash.compact!(h))                # => nil
```

```ruby error
p(Hash.size(Hash.compact!(Hash.of("a" => 1))))   # !> Hash.size: argument 1 may be nil
```

## slice

`Hash.slice(x, *Any)`

列挙したキーの組だけを持つ新しい Hash を返します。無いキーは無視され、順序は列挙した順です。

```ruby
h = Hash.of("a" => 1, "b" => 2, "c" => 3)
p(Hash.slice(h, "c", "a", "zz"))   # => {"c" => 3, "a" => 1}
```

## except

`Hash.except(x, *Any)`

列挙したキーの組を除いた新しい Hash を返します。無いキーは無視されます。

```ruby
h = Hash.of("a" => 1, "b" => 2, "c" => 3)
p(Hash.except(h, "a", "zz"))       # => {"b" => 2, "c" => 3}
```

## invert

`Hash.invert(x)`

値をキー、キーを値にした新しい Hash を返します。値はキーにできるものでなければならず（`TypeError`）、同じ値が複数あれば後の組が残ります。結果のキーの型と値の型は元の値の型とキーの型です。

```ruby
p(Hash.invert(Hash.of("a" => 1, "b" => 2)))        # => {1 => "a", 2 => "b"}
p(Hash.invert(Hash.of("a" => 1, "b" => 1)))        # => {1 => "b"}
```

```ruby error
Hash.invert(Hash.of("a" => /x/))      # !> TypeError: Hash.invert: Regexp cannot be a Hash key or Set element
```

## delete

`Hash.delete(x, Any)`

キー `k` の組を取り除き、その値を返します。無ければ nil で、level 2 で報告されます（default は見ません）。Ruby のブロック形はありません。

```ruby
h = Hash.of("a" => 1, "b" => 2)
p(Hash.delete(h, "a"))             # => 1
p(Hash.delete(h, "zz"))            # => nil
p(h)                               # => {"b" => 2}
```

```ruby error
h = Hash.of("a" => 1)
p(Hash.delete(h, "a") + 1)         # !> the operands may be nil
```

## delete_if

`Hash.delete_if(x) { }`

ブロックが真を返した組をその場で取り除き、Hash 自身を返します（取り除かなくても nil にはなりません。`reject!` との違い）。

```ruby
h = Hash.of("a" => 1, "b" => 2, "c" => 3)
p(Hash.delete_if(h) { |k, v| v > 1 })   # => {"a" => 1}
p(Hash.delete_if(h) { |k, v| false })   # => {"a" => 1}
```

## keep_if

`Hash.keep_if(x) { }`

ブロックが真を返した組だけをその場で残し、Hash 自身を返します（変化が無くても nil にはなりません。`select!` との違い）。

```ruby
h = Hash.of("a" => 1, "b" => 2, "c" => 3)
p(Hash.keep_if(h) { |k, v| v > 1 })   # => {"b" => 2, "c" => 3}
```

## select!, filter!

`Hash.select!(x) { }`

`Hash.filter!(x) { }`

ブロックが真を返した組だけをその場で残し、Hash 自身を返します。1 つも取り除かなかったときは nil（Ruby と同じ）で、戻り値をそのまま使うと level 2 で報告されます。常に Hash を返す形は `keep_if`。

```ruby
h = Hash.of("a" => 1, "b" => 2, "c" => 3)
p(Hash.select!(h) { |k, v| v > 1 })   # => {"b" => 2, "c" => 3}
p(Hash.filter!(h) { |k, v| v > 1 })   # => nil
p(h)                                  # => {"b" => 2, "c" => 3}
```

## reject!

`Hash.reject!(x) { }`

ブロックが真を返した組をその場で取り除き、Hash 自身を返します。1 つも取り除かなかったときは nil（level 2 で報告）。常に Hash を返す形は `delete_if`。

```ruby
h = Hash.of("a" => 1, "b" => 2, "c" => 3)
p(Hash.reject!(h) { |k, v| v > 2 })   # => {"a" => 1, "b" => 2}
p(Hash.reject!(h) { |k, v| v > 5 })   # => nil
```

## shift

`Hash.shift(x)`

最初に挿入された組を取り除き、`[k, v]` の Tuple で返します。空なら nil（default は見ません。level 2 で報告）。

```ruby
h = Hash.of("a" => 1, "b" => 2)
p(Hash.shift(h))                   # => ["a", 1]
p(h)                               # => {"b" => 2}
Hash.shift(h)
p(Hash.shift(h))                   # => nil
```

## clear

`Hash.clear(x)`

すべての組を取り除き、Hash 自身（空）を返します。default はそのままです。

```ruby
h = Hash.of("a" => 1)
p(Hash.clear(h))                   # => {}
p(Hash.empty?(h))                  # => true
```

## ==, !=

`Hash.==(x, Any)`

`Hash.!=(x, Any)`

2 つの Hash が同じキーの集合を持ち、各キーの値が `==` で等しいときに true（`!=` はその否定）。挿入順は関係ありません。default も見ません。右側が Hash でない値（nil、Integer、Array）とは等しくなく、関数形も演算子と同じです: `Hash.==(h, nil)` は false。Record `{a: 1}` と `Hash.of(a: 1)` は型が違うので等しくありません。

```ruby
a = Hash.of("a" => 1, "b" => 2)
p(a == Hash.of("b" => 2, "a" => 1))   # => true
p(a != Hash.of("a" => 1))             # => true
p(Hash.==(a, Hash.new))              # => false
p(Hash.==(a, nil))                 # => false
p(Hash.!=(a, 1))                   # => true
p(Hash.of(a: 1) == {a: 1})            # => false
```

# Record

Record はフィールド名と値の組の集まりで、リテラル `{x: 1, y: "a"}` が作ります（[値と型](../03-values.md)）。Ruby ではこの書き方は Hash ですが、Sake では **Record であって Hash ではありません**。Hash は `Hash.of(x: 1)` で作ります（[Hash](Hash.md)）。`{}`（空）と `{"a" => 1}`（`=>` 形）は静的に拒否されます。

Record の型はその (フィールド名, 型) の集合で、`{x: Integer, y: String}` のように表されます。同じ集合を持つ Record は同じ型です。フィールドの順序は型に関係なく、`{y: 2, x: 1}` は `{x: 1, y: 2}` と表示されます。クラスのインスタンスとは別物です（クラスは名前で、Record 型は構造で区別されます。[クラス](../07-classes.md)）。

フィールドはパターンで読みます: `r => {x:, y: name}` は局所変数 `x` にフィールド `x`、`name` にフィールド `y` を束縛します。一部のフィールドだけを挙げてもよく、`case r in {x:} ... end` も同じパターンです。無いフィールドを挙げると静的に `type` の問題（実行時なら `KeyError`）、Record でない値に当てても静的に `type` の問題（実行時なら `TypeError`）です。フィールドへの書き込み（`r.x = v`、`r[:x] = v`）はまだありません（どちらも静的に拒否。`Indexable.[]=` は Record を受け付けません）。

Record に使える演算子は `==`、`!=` です（同じフィールドの集合を持ち、各値が等しいとき true）。添字 `r[:x]` はありません。

この章の 3 つの操作は、Record をデータとして扱う（任意の Record を歩く）ためのものです。引数の型は `Any` で、Record 以外を渡すと実行時に `TypeError` です。結果のフィールド順はフィールド名の順（表示と同じ）です。

## keys

`Record.keys(Any)`

フィールド名を Symbol にした新しい Array を返します。順序はフィールド名の順で、リテラルに書いた順ではありません。

```ruby
r = {x: 1, y: "a"}
p(Record.keys(r))                  # => [:x, :y]
p(Record.keys({y: 2, x: 1}))       # => [:x, :y]
```

```ruby error
p(Record.keys(Hash.of(x: 1)))         # !> TypeError: Record.keys: argument 1 must be a Record, got Hash
```

## values

`Record.values(Any)`

フィールドの値を `keys` と同じ順に並べた新しい Array を返します。Record とは独立で、Array の方は伸ばせます。要素の型は各フィールドの型の和です。

```ruby
r = {x: 1, y: "a"}
vs = Record.values(r)
p(vs)                              # => [1, "a"]
Array.push(vs, 3)
p(r)                               # => {x: 1, y: "a"}
```

## to_h

`Record.to_h(Any)`

フィールド名を Symbol キーとする新しい Hash を返します。検査器にとってキーの型は Symbol、値の型は各フィールドの型の和なので、フィールドの型が違う Record では `h[:x]` の値をそのまま計算に使うと `type` の問題になります（Hash は値の型を 1 つしか持てないため）。フィールドの型がそろっていれば普通の Hash として使えます。入れ子の Record は Record のまま値になります。

```ruby
r = {x: 1, y: 2}
h = Record.to_h(r)
p(h)                               # => {x: 1, y: 2}
p(Hash.fetch(h, :x) + Hash.fetch(h, :y))   # => 3
p(Record.to_h({name: "a", pos: {x: 1}}))   # => {name: "a", pos: {x: 1}}
```

```ruby error
h = Record.to_h({x: 1, y: "a"})
p(Hash.fetch(h, :x) + 1)           # !> which the left operand's type does not support
```

# Set

Set は重複の無い要素の集まりです。`Set.of(1, 2)` が Set を作り、`Set.new(xs)` は Array の要素から Set を作ります（Ruby の `Set.new([1, 2])`）。要素は Hash のキーと同じ規則で区別されます: Integer, Float, String, Symbol, true, false, nil, Time と、それらからなる Tuple, Record, Array, Hash, Set, クラスのインスタンスが要素になれ、Regexp, Range, 自分の等価（`==` か `Comparable`）を定義したクラスの値は実行時に `TypeError` です。同じ要素かどうかは Ruby の Hash と同じく `hash` と `eql?` で決まるので、`1` と `1.0` は別の要素です。要素は追加した順に並び、反復もその順です。要素に使った String は複製が入るので、後で元の String を変えても Set は変わりません。

検査器は Set の要素の型を構築した場所ごとに追い、`Set.add` などの書き込みで広げます。ブロックを取る操作のブロックは、その要素の型の値を受け取ります。

Set に使える演算子は `|`（和）、`&`（積）、`-`（差）、`==`、`!=` です。`^`、`+`、`<`、`<=` などは使えず、部分集合の判定は `Set.subset?` などで行います。下の `Set.|(x, y)` などは演算子を関数の形で呼ぶものです（[演算子と添字](../05-operators.md)）。要素を取り出す多くの操作（`select`、`map`、`sort`、`to_a` など）は Set ではなく **Array** を返します。Ruby の `Set#select` が Set を返すのとは違います。

## of

`Set.of(*Any)`

要素を並べて Set を作ります。重複した要素は 1 つになります。要素になれない値（Regexp, Range, 自分の等価を定義した クラスのインスタンス）は実行時に `TypeError`。`Set.new` は空の Set で、後から `Set.add` で要素を入れると要素の型がそれに広がります。

```ruby
s = Set.of(1, 2, 2, 3)
p(s)                          # => Set[1, 2, 3]
p(Set.new)                      # => Set[]
p(Set.size(Set.of(1, 1.0)))      # => 2
```

```ruby error
p(Set.of(/a/))                   # !> TypeError: Set.of: Regexp cannot be a Hash key or Set element
```

## new

`Set.new([Array])`

Array の要素から Set を作ります（Ruby の `Set.new([1, 2])`）。引数の無い `Set.new` は空の Set です。重複した要素は 1 つになり、要素になれない値は `TypeError`。

```ruby
p(Set.new(Any[3, 1, 3]))         # => Set[3, 1]
p(Set.new)                       # => Set[]
```

## Set[]

`Set[*Any]`

Set の Array を作ります。どの T でも `T[...]` が T の Array を作るのと同じで、各要素は Set でなければならず、書き込みのたびに検査されます。

```ruby
ss = Set[Set.of(1), Set.new]
p(ss)                            # => [Set[1], Set[]]
```

## length, size

`Set.length(x)`

`Set.size(x)`

要素の個数（Integer）。

```ruby
p(Set.size(Set.of(1, 2, 3)))     # => 3
p(Set.length(Set.new))          # => 0
```

## empty?

`Set.empty?(x)`

要素が無いとき true。

```ruby
p(Set.empty?(Set.new))          # => true
p(Set.empty?(Set.of(1)))         # => false
```

## include?, member?

`Set.include?(x, Any)`

`Set.member?(x, Any)`

値が要素にあるとき true。要素の比較は Hash のキーと同じ（`hash` と `eql?`）なので、`1` の入った Set に `1.0` はありません。Set の要素の型と違う型の値を聞いても静的な問題にはならず、false です。

```ruby
s = Set.of(1, 2)
p(Set.include?(s, 1))         # => true
p(Set.include?(s, 1.0))       # => false
p(Set.member?(s, "a"))        # => false
p(Set.include?(Set.of([1, 2]), [1, 2]))   # => true
```

## add

`Set.add(x, Any)`

値を要素に加え、Set 自身を返します（その場で変更）。すでにある値なら何も変わりません。要素になれない値は実行時に `TypeError`。加えた値の型は、その Set の要素の型に加わります。

```ruby
s = Set.of(1)
p(Set.add(s, 2))              # => Set[1, 2]
p(Set.add(s, 2))              # => Set[1, 2]
p(s)                          # => Set[1, 2]
```

```ruby error
Set.add(Set.of(1), 1..2)         # !> TypeError: Set.add: Range cannot be a Hash key or Set element
```

## add?

`Set.add?(x, Any)`

`add` と同じですが、その値がすでにあったときは **nil** を返します（新しく加えたときは Set 自身）。戻り値は Set か nil なので、`--strict`（レベル 2）は確かめずに使うと報告します。「初めて見た値か」の判定に使います。

```ruby
s = Set.of(1)
p(Set.add?(s, 2))             # => Set[1, 2]
p(Set.add?(s, 2))             # => nil
```

```ruby error
s = Set.of(1)
x = Set.add?(s, 2)
p(Set.size(x))                # !> argument 1 may be nil
```

## delete

`Set.delete(x, Any)`

値を要素から取り除き、Set 自身を返します（その場で変更）。無い値なら何も変わりません。Ruby と同じです。

```ruby
s = Set.of(1, 2, 3)
p(Set.delete(s, 2))           # => Set[1, 3]
p(Set.delete(s, 99))          # => Set[1, 3]
```

## delete?

`Set.delete?(x, Any)`

`delete` と同じですが、その値が無かったときは **nil** を返します（取り除いたときは Set 自身）。戻り値は `--strict`（レベル 2）で確かめずに使うと報告されます。

```ruby
s = Set.of(1, 2)
p(Set.delete?(s, 2))          # => Set[1]
p(Set.delete?(s, 2))          # => nil
```

## merge

`Set.merge(x, Set)`

もう一方の Set の要素をすべて加え、Set 自身を返します（その場で変更）。引数は Set でなければなりません（Array は静的に `type` の問題。Ruby の `merge` は任意の列挙を取ります）。新しい Set が欲しいときは `|` か `union` を使います。

```ruby
s = Set.of(1, 2)
p(Set.merge(s, Set.of(2, 3)))    # => Set[1, 2, 3]
p(s)                          # => Set[1, 2, 3]
```

```ruby error
Set.merge(Set.of(1), Any[2])   # !> argument 2 must be Set, but is Array
```

## subtract

`Set.subtract(x, Any)`

引数に含まれる要素をすべて取り除き、Set 自身を返します（その場で変更）。引数は Set、Array、Tuple、Range のいずれかです。検査器は調べず（署名は `Any`）、それ以外は実行時に `TypeError`（`argument 2 must be Set, Array, Tuple, or Range, got Integer`）。新しい Set が欲しいときは `-` か `difference` を使います。

```ruby
s = Set.of(1, 2, 3, 4, 5)
p(Set.subtract(s, Set.of(1)))    # => Set[2, 3, 4, 5]
p(Set.subtract(s, Any[2]))  # => Set[3, 4, 5]
p(Set.subtract(s, [3]))       # => Set[4, 5]
p(Set.subtract(s, 4..4))      # => Set[5]
p(s)                          # => Set[5]
```

```ruby error
Set.subtract(Set.of(1, 2), 1)    # !> TypeError: Set.subtract: argument 2 must be Set, Array, Tuple, or Range, got Integer
```

## replace

`Set.replace(x, Set)`

要素をすべてもう一方の Set の要素に置き換え、Set 自身を返します（その場で変更）。もう一方の要素の型がこの Set の要素の型に加わります。

```ruby
s = Set.of(1, 2)
p(Set.replace(s, Set.of(7, 8)))  # => Set[7, 8]
p(s)                          # => Set[7, 8]
```

## clear

`Set.clear(x)`

要素をすべて取り除き、空になった Set 自身を返します。

```ruby
s = Set.of(1, 2)
p(Set.clear(s))               # => Set[]
p(Set.empty?(s))              # => true
```

## |, union

`Set.|(x, Any)`

`Set.union(x, Set)`

和集合: 両方の要素をすべて持つ **新しい** Set。`a | b` の関数形が `Set.|`。右側は Set でなければならず、Array などは静的に `type` の問題です。結果の要素の型は両方の要素の型の和です。

```ruby
a = Set.of(1, 2)
b = Set.of(2, 3)
p(a | b)                      # => Set[1, 2, 3]
p(Set.union(a, b))            # => Set[1, 2, 3]
p(a)                          # => Set[1, 2]
```

```ruby error
p(Set.of(1) | Any[2])          # !> Bitwise.|: the operands are (Set@L1[Integer], Array@L1[Integer])
```

## &, intersection

`Set.&(x, Any)`

`Set.intersection(x, Set)`

積集合: 両方にある要素だけの **新しい** Set。`a & b` の関数形が `Set.&`。右側は Set でなければなりません。

```ruby
a = Set.of(1, 2, 3)
b = Set.of(2, 3, 4)
p(a & b)                      # => Set[2, 3]
p(Set.intersection(a, b))     # => Set[2, 3]
```

## -, difference

`Set.-(x, Any)`

`Set.difference(x, Set)`

差集合: 左にあって右に無い要素の **新しい** Set。`a - b` の関数形が `Set.-`。右側は Set でなければなりません。

```ruby
a = Set.of(1, 2, 3)
b = Set.of(2)
p(a - b)                      # => Set[1, 3]
p(Set.difference(a, b))       # => Set[1, 3]
p(a)                          # => Set[1, 2, 3]
```

## ==, !=

`Set.==(x, Any)`

`Set.!=(x, Any)`

2 つの Set が同じ要素を持つとき true（順序は関係ありません。`!=` はその否定）。右側が Set 以外（Array や nil）なら等しくありません。

```ruby
p(Set.of(1, 2) == Set.of(2, 1))     # => true
p(Set.of(1, 2) == Set.of(1))        # => false
p(Set.of(1) != Set.of(1))           # => false
p(Set.of(1, 2) == Any[1, 2])   # => false
```

## subset?, superset?

`Set.subset?(x, Set)`

`Set.superset?(x, Set)`

`subset?` は x のすべての要素が引数の Set にあるとき true、`superset?` はその逆です。等しい Set 同士も true。引数は Set でなければなりません（Array は静的に `type` の問題）。Ruby の `<=`、`>=` 演算子は Set には使えないので、これらの関数を使います。

```ruby
a = Set.of(1, 2)
b = Set.of(1, 2, 3)
p(Set.subset?(a, b))          # => true
p(Set.subset?(a, a))          # => true
p(Set.superset?(b, a))        # => true
p(Set.superset?(a, b))        # => false
```

```ruby error
p(Set.of(1) <= Set.of(1, 2))        # !> Comparable.<=: the operands are (Set@L1[Integer], Set@L1[Integer])
```

## proper_subset?, proper_superset?

`Set.proper_subset?(x, Set)`

`Set.proper_superset?(x, Set)`

真部分集合の判定: `subset?`、`superset?` と同じですが、等しい Set 同士は false です（Ruby の `<`、`>`）。

```ruby
a = Set.of(1, 2)
b = Set.of(1, 2, 3)
p(Set.proper_subset?(a, b))   # => true
p(Set.proper_subset?(a, a))   # => false
p(Set.proper_superset?(b, a)) # => true
```

## disjoint?, intersect?

`Set.disjoint?(x, Set)`

`Set.intersect?(x, Set)`

`intersect?` は共通の要素が 1 つでもあるとき true、`disjoint?` はその否定です。

```ruby
p(Set.intersect?(Set.of(1, 2), Set.of(2, 3)))   # => true
p(Set.disjoint?(Set.of(1, 2), Set.of(2, 3)))    # => false
p(Set.disjoint?(Set.of(1), Set.of(9)))          # => true
```

## each, each_entry

`Set.each(x) { }`

`Set.each_entry(x) { }`

要素を加えた順にブロックへ 1 つずつ渡し、Set 自身を返します。ブロックは必須です（Ruby のようにブロック無しで Enumerator を得ることはできません）。

```ruby
s = Set.of(3, 1, 2)
Set.each(s) { |x| puts(x) }
# => 3
# => 1
# => 2
p(Set.each_entry(s) { |x| x })   # => Set[3, 1, 2]
```

## each_with_index

`Set.each_with_index(x) { }`

要素とその位置（0 から）をブロックへ渡し、Set 自身を返します。

```ruby
Set.each_with_index(Set.of("a", "b")) { |x, i| puts("#{i}: #{x}") }
# => 0: a
# => 1: b
```

## each_with_object

`Set.each_with_object(x, Any) { }`

要素と第 2 引数の値をブロックへ渡して回り、第 2 引数の値を返します。累積用の Array や Hash を渡す形で使います。

```ruby
a = Set.each_with_object(Set.of(1, 2), Any[]) { |x, acc| Array.push(acc, x * 2) }
p(a)                          # => [2, 4]
```

## reverse_each

`Set.reverse_each(x) { }`

要素を加えた順の逆にブロックへ渡し、Set 自身を返します。

```ruby
Set.reverse_each(Set.of(1, 2, 3)) { |x| puts(x) }
# => 3
# => 2
# => 1
```

## each_slice, each_cons

`Set.each_slice(x, Integer) { }`

`Set.each_cons(x, Integer) { }`

`each_slice` は要素を n 個ずつの Array に切ってブロックへ渡し（最後は短くてよい）、`each_cons` は連続する n 個の Array を 1 つずつずらして渡します。どちらも Set 自身を返します。n が 0 以下なら `ArgumentError`。

```ruby
s = Set.of(1, 2, 3, 4)
Set.each_slice(s, 3) { |a| p(a) }
# => [1, 2, 3]
# => [4]
Set.each_cons(s, 3) { |a| p(a) }
# => [1, 2, 3]
# => [2, 3, 4]
```

```ruby error
Set.each_slice(Set.of(1), 0) { |a| p(a) }   # !> ArgumentError: Set.each_slice: invalid slice size
```

## cycle

`Set.cycle(x, Integer) { }`

要素の列を n 回繰り返してブロックへ渡し、**nil** を返します。回数は必須です（Ruby の無限の `cycle` はありません）。n が 0 以下なら何もしません。

```ruby
Set.cycle(Set.of(1, 2), 2) { |x| print(x) }
puts("")
# => 1212
p(Set.cycle(Set.of(1), 0) { |x| p(x) })   # => nil
```

## map, collect

`Set.map(x) { }`

`Set.collect(x) { }`

各要素にブロックを適用した結果の **Array**（Set ではありません。要素の順に並び、重複もそのまま）。要素の型はブロックの結果の型です。

```ruby
p(Set.map(Set.of(1, 2, 3)) { |x| x * 10 })        # => [10, 20, 30]
p(Set.collect(Set.of(1, 2, 3)) { |x| x % 2 })     # => [1, 0, 1]
```

## map!, collect!

`Set.map!(x) { }`

`Set.collect!(x) { }`

各要素をブロックの結果に置き換え、Set 自身を返します（その場で変更）。結果が重なれば要素は減ります。ブロックの結果の型が要素の型に加わります。要素になれない値を返すと実行時に `TypeError`。

```ruby
s = Set.of(1, 2, 3)
p(Set.map!(s) { |x| x % 2 })  # => Set[1, 0]
p(s)                          # => Set[1, 0]
```

## flat_map, collect_concat

`Set.flat_map(x) { }`

`Set.collect_concat(x) { }`

ブロックは各要素に対して **Array か Tuple** を返し、それらをつなげた 1 つの Array が結果です。ブロックがどちらでもない値を返すと実行時に `TypeError`（`the block must return an Array or a Tuple, got Integer`。Ruby のように値をそのまま並べはしません）。

```ruby
p(Set.flat_map(Set.of(1, 2)) { |x| Any[x, x * 10] })   # => [1, 10, 2, 20]
p(Set.flat_map(Set.of(1, 2)) { |x| [x, x * 10] })        # => [1, 10, 2, 20]
```

```ruby error
Set.flat_map(Set.of(1)) { |x| x }    # !> TypeError: Set.flat_map: the block must return an Array or a Tuple, got Integer
```

## select, filter, find_all

`Set.select(x) { }`

`Set.filter(x) { }`

`Set.find_all(x) { }`

ブロックが真を返した要素の **Array**（Ruby の `Set#select` は Set を返しますが、Sake では Array です）。Set が欲しいときは `select!` でその場で絞るか、`Set.of(*...)` ではなく `Array.to_set` を使います。

```ruby
s = Set.of(1, 2, 3, 4)
p(Set.select(s) { |x| Integer.even?(x) })      # => [2, 4]
p(Set.filter(s) { |x| x > 3 })                 # => [4]
p(Set.find_all(s) { |x| x < 0 })               # => []
```

## reject

`Set.reject(x) { }`

ブロックが偽を返した要素の **Array**（`select` の逆）。

```ruby
p(Set.reject(Set.of(1, 2, 3, 4)) { |x| Integer.even?(x) })   # => [1, 3]
```

## select!, filter!, reject!

`Set.select!(x) { }`

`Set.filter!(x) { }`

`Set.reject!(x) { }`

`select!`、`filter!` はブロックが偽の要素を、`reject!` はブロックが真の要素をその場で取り除きます。何か取り除いたときは Set 自身、**何も変わらなかったときは nil** を返します（Ruby と同じ）。戻り値は `--strict`（レベル 2）で確かめずに使うと報告されます。常に Set を返す形は `keep_if`、`delete_if` です。

```ruby
s = Set.of(1, 2, 3, 4)
p(Set.select!(s) { |x| x > 1 })    # => Set[2, 3, 4]
p(Set.select!(s) { |x| x > 1 })    # => nil
p(Set.reject!(s) { |x| x > 3 })    # => Set[2, 3]
p(Set.filter!(s) { |x| x < 9 })    # => nil
p(s)                               # => Set[2, 3]
```

## keep_if, delete_if

`Set.keep_if(x) { }`

`Set.delete_if(x) { }`

`keep_if` はブロックが真の要素だけを残し、`delete_if` はブロックが真の要素を取り除きます（その場で変更）。どちらも常に Set 自身を返します。

```ruby
s = Set.of(1, 2, 3, 4)
p(Set.keep_if(s) { |x| x > 1 })        # => Set[2, 3, 4]
p(Set.delete_if(s) { |x| x > 3 })      # => Set[2, 3]
p(Set.delete_if(s) { |x| x > 9 })      # => Set[2, 3]
```

## filter_map

`Set.filter_map(x) { }`

各要素にブロックを適用し、nil と false でない結果だけを集めた Array。結果の要素の型からは nil が除かれます。

```ruby
p(Set.filter_map(Set.of(1, 2, 3, 4)) { |x| Integer.even?(x) ? x * 10 : nil })   # => [20, 40]
```

## partition

`Set.partition(x) { }`

ブロックが真の要素の Array と偽の要素の Array の Tuple `[yes, no]`。

```ruby
ev, od = Set.partition(Set.of(1, 2, 3, 4)) { |x| Integer.even?(x) }
p(ev)                         # => [2, 4]
p(od)                         # => [1, 3]
```

## group_by

`Set.group_by(x) { }`

ブロックの結果をキー、その結果になった要素の Array を値とする Hash。キーになれない値を返すと実行時に `TypeError`。

```ruby
p(Set.group_by(Set.of(1, 2, 3, 4)) { |x| x % 2 })    # => {1 => [1, 3], 0 => [2, 4]}
```

## classify

`Set.classify(x) { }`

`group_by` と同じ分け方で、値が Array ではなく **Set** の Hash を返します（Ruby の `Set#classify`）。

```ruby
p(Set.classify(Set.of(1, 2, 3, 4)) { |x| x % 2 })    # => {1 => Set[1, 3], 0 => Set[2, 4]}
```

## tally

`Set.tally(x)`

要素をキー、その個数を値とする Hash。Set の要素は重複しないので値はすべて 1 です（Array から来た操作で、形をそろえるためにあります）。

```ruby
p(Set.tally(Set.of("a", "b")))   # => {"a" => 1, "b" => 1}
```

## chunk_while, slice_when

`Set.chunk_while(x) { }`

`Set.slice_when(x) { }`

隣り合う 2 要素をブロックに渡し、`chunk_while` はブロックが真の間を 1 つの区間に、`slice_when` はブロックが真のところで区切ります。結果は Array の Array です。

```ruby
s = Set.of(1, 2, 4, 5, 7)
p(Set.chunk_while(s) { |a, b| b == a + 1 })   # => [[1, 2], [4, 5], [7]]
p(Set.slice_when(s) { |a, b| b > a + 1 })     # => [[1, 2], [4, 5], [7]]
```

## slice_before, slice_after

`Set.slice_before(x) { }`

`Set.slice_after(x) { }`

ブロックが真を返す要素の直前（`slice_before`）または直後（`slice_after`）で区切った、Array の Array。

```ruby
s = Set.of(1, 2, 3, 4)
p(Set.slice_before(s) { |x| x == 3 })   # => [[1, 2], [3, 4]]
p(Set.slice_after(s) { |x| x == 2 })    # => [[1, 2], [3, 4]]
```

## find, detect

`Set.find(x) { }`

`Set.detect(x) { }`

ブロックが真を返した最初の要素。どの要素も真にならなければ **nil** で、`--strict`（レベル 2）は確かめずに使うと報告します。

```ruby
s = Set.of(1, 2, 3)
p(Set.find(s) { |x| x > 1 })      # => 2
p(Set.detect(s) { |x| x > 9 })    # => nil
```

```ruby error
x = Set.find(Set.of(1)) { |v| v > 0 }
p(x + 1)                          # !> the operands may be nil
```

## find_index

`Set.find_index(x) { }`

ブロックが真を返した最初の要素の位置（Integer、加えた順で 0 から）。無ければ **nil**（`--strict` レベル 2 で報告）。

```ruby
s = Set.of("a", "b", "c")
p(Set.find_index(s) { |x| x == "c" })   # => 2
p(Set.find_index(s) { |x| x == "z" })   # => nil
```

## any?, all?, none?, one?

`Set.any?(x) { }`

`Set.all?(x) { }`

`Set.none?(x) { }`

`Set.one?(x) { }`

ブロックが真を返す要素が、1 つ以上ある・すべてである・1 つも無い・ちょうど 1 つあるとき true。ブロックは必須です（Ruby のブロック無しの形はありません。空かどうかは `empty?`）。

```ruby
s = Set.of(1, 2, 3)
p(Set.any?(s) { |x| x > 2 })      # => true
p(Set.all?(s) { |x| x > 2 })      # => false
p(Set.none?(s) { |x| x > 9 })     # => true
p(Set.one?(s) { |x| x == 1 })     # => true
```

```ruby error
p(Set.any?(Set.of(1)))               # !> Set.any? requires a block
```

## count

`Set.count(x) [{ }]`

ブロック無しなら要素の個数、ブロック付きならブロックが真を返した要素の個数（Integer）。

```ruby
s = Set.of(1, 2, 3)
p(Set.count(s))                   # => 3
p(Set.count(s) { |x| x > 1 })     # => 2
```

## sum

`Set.sum(x, [Integer|Float|Rational|Complex])`

要素の和。初期値（省略時 0）に要素を順に足します。要素と初期値は数でなければならず、初期値に String などを渡すのは静的に `type` の問題、数でない要素は実行時に `TypeError`（`String can't be coerced into Integer`）です（Ruby の `sum("")` で String をつなぐ形はありません。`join` を使います）。空の Set では初期値。

```ruby
p(Set.sum(Set.of(1, 2, 3)))          # => 6
p(Set.sum(Set.of(1, 2), 0.5))        # => 3.5
p(Set.sum(Set.new))                 # => 0
```

```ruby error
p(Set.sum(Set.of("a", "b"), ""))     # !> argument 2 must be Integer|Float|Rational|Complex, but is String
```

## reduce, inject

`Set.reduce(x, Any) { }`

`Set.inject(x, Any) { }`

初期値から始め、ブロックに累積値と要素を渡して畳み込みます。初期値は **必須** です（Ruby の、最初の要素を初期値にする形はありません）。結果の型は初期値とブロックの結果の型から決まります。

```ruby
p(Set.reduce(Set.of(1, 2, 3), 0) { |acc, x| acc + x })     # => 6
p(Set.inject(Set.of(1, 2, 3), 1) { |acc, x| acc * x })     # => 6
```

```ruby error
p(Set.reduce(Set.of(1)) { |a, b| a + b })   # !> wrong number of arguments for Set.reduce (given 1, expected 2)
```

## min, max

`Set.min(x)`

`Set.max(x)`

最小・最大の要素。要素は互いに比べられなければなりません: 比べられない型が要素の型に混ざる Set（`Set.of(1, "a")`）は検査器が静的に `type` の問題として退け、nil になりうる要素は `nil` の問題です。検査器に見えないとき（`Set.of(1.0, Float.NAN)`）は実行時に `ArgumentError`（`cannot compare the elements`）。空の Set では **nil** で、`Array.min` と同じ外れの nil です: 確かめずに使うことは `--strict=3` でだけ報告されます。

```ruby
s = Set.of(3, 1, 2)
p(Set.min(s))                     # => 1
p(Set.max(s))                     # => 3
p(Set.max(Set.new))                 # => nil
```

```ruby error
p(Set.min(Set.of(1, "a")))           # !> Set.min: elements compared in order may be (Integer, String), which cannot be compared
```

```ruby error
p(Set.min(Set.of(1.0, Float.NAN)))   # !> ArgumentError: Set.min: cannot compare the elements
```

## minmax

`Set.minmax(x)`

最小と最大の Tuple `[min, max]`。空の Set では `[nil, nil]` で、これは外れの nil です（要素を確かめずに使うことは `--strict=3` でだけ報告）。比較の規則は静的な検査を含めて `min`、`max` と同じ。

```ruby
lo, hi = Set.minmax(Set.of(3, 1, 2))
p([lo, hi])                       # => [1, 3]
p(Set.minmax(Set.new))              # => [nil, nil]
```

## min_by, max_by

`Set.min_by(x) { }`

`Set.max_by(x) { }`

ブロックの結果が最小・最大になる要素。ブロックの結果同士は比べられなければならず、比べられない型が結果の型に混ざるブロックは `min` と同じく静的に退けられます（`type`）。空の Set では **nil** で、外れの nil です（`--strict=3` でだけ報告）。

```ruby
s = Set.of("bb", "a", "ccc")
p(Set.min_by(s) { |x| String.size(x) })   # => "a"
p(Set.max_by(s) { |x| String.size(x) })   # => "ccc"
p(Set.max_by(Set.new) { |x| x })            # => nil
```

```ruby error
p(Set.min_by(Set.of(1, 2)) { |x| x == 1 ? 1 : "a" })   # !> Set.min_by: elements compared in order may be (Integer, String), which cannot be compared
```

## minmax_by

`Set.minmax_by(x) { }`

ブロックの結果で見た最小と最大の要素の Tuple。空の Set では `[nil, nil]`（外れの nil、レベル 3）。ブロックの結果の検査は `min_by` と同じ。

```ruby
p(Set.minmax_by(Set.of(1, 2, 3)) { |x| -x })   # => [3, 1]
```

## sort

`Set.sort(x)`

要素を昇順に並べた Array。要素は互いに比べられなければなりません: 比べられない型が要素の型に混ざる Set は静的に退けられ（`type`）、nil になりうる要素は `nil` の問題です。検査器に見えないとき（`Set.of(1.0, Float.NAN)`）は実行時に `ArgumentError`（`cannot compare the elements`）。

```ruby
p(Set.sort(Set.of(3, 1, 2)))         # => [1, 2, 3]
```

```ruby error
p(Set.sort(Set.of(1, "a")))          # !> Set.sort: elements compared in order may be (Integer, String), which cannot be compared
```

## sort_by

`Set.sort_by(x) { }`

ブロックの結果の昇順に要素を並べた Array。Tuple を返すと辞書順で並びます。ブロックの結果同士は比べられなければならず、比べられない型が結果の型に混ざると静的に退けられます（`type`）。

```ruby
p(Set.sort_by(Set.of("bb", "a", "ccc")) { |x| String.size(x) })   # => ["a", "bb", "ccc"]
p(Set.sort_by(Set.of(1, 2, 3)) { |x| -x })                        # => [3, 2, 1]
```

```ruby error
p(Set.sort_by(Set.of(1, 2)) { |x| x == 1 ? 1 : "a" })   # !> Set.sort_by: elements compared in order may be (Integer, String), which cannot be compared
```

## first

`Set.first(x)`

最初に加えた要素。空の Set では **nil** で、`Array.first` と同じ外れの nil です: 確かめずに使うことは `--strict=3` でだけ報告されます。個数を指定する形はありません（`take` を使います）。

```ruby
p(Set.first(Set.of(3, 1)))           # => 3
p(Set.first(Set.new))               # => nil
```

## take, drop

`Set.take(x, Integer)`

`Set.drop(x, Integer)`

先頭の n 要素の Array、先頭の n 要素を除いた残りの Array。n が負なら `ArgumentError`。

```ruby
s = Set.of(1, 2, 3, 4)
p(Set.take(s, 2))                 # => [1, 2]
p(Set.drop(s, 2))                 # => [3, 4]
p(Set.take(s, 9))                 # => [1, 2, 3, 4]
```

```ruby error
p(Set.take(Set.of(1), -1))           # !> ArgumentError: Set.take: attempt to take negative size
```

## take_while, drop_while

`Set.take_while(x) { }`

`Set.drop_while(x) { }`

先頭からブロックが真の間の要素の Array、その残りの Array。

```ruby
s = Set.of(1, 2, 3, 1)
p(Set.take_while(s) { |x| x < 3 })    # => [1, 2]
p(Set.drop_while(s) { |x| x < 3 })    # => [3]
```

## to_a, entries

`Set.to_a(x)`

`Set.entries(x)`

要素を加えた順に並べた新しい Array。Array を変えても Set は変わりません。

```ruby
s = Set.of(3, 1)
a = Set.to_a(s)
Array.push(a, 9)
p(a)                              # => [3, 1, 9]
p(s)                              # => Set[3, 1]
p(Set.entries(s))                 # => [3, 1]
```

## to_set

`Set.to_set(x)`

Set 自身を返します（複製ではありません）。Array の `Array.to_set` と形をそろえるための操作です。

```ruby
s = Set.of(1)
Set.add(Set.to_set(s), 2)
p(s)                              # => Set[1, 2]
```

## uniq

`Set.uniq(x)`

要素の Array。Set に重複は無いので `to_a` と同じです。

```ruby
p(Set.uniq(Set.of(1, 2)))            # => [1, 2]
```

## compact

`Set.compact(x)`

nil を除いた要素の Array。

```ruby
p(Set.compact(Set.of(1, nil, 2)))    # => [1, 2]
```

## flatten

`Set.flatten(x)`

要素の Set を再帰的に開いた **新しい Set**（Ruby の `Set#flatten`）。Array の要素は開きません。

```ruby
p(Set.flatten(Set.of(1, Set.of(2, Set.of(3)))))   # => Set[1, 2, 3]
p(Set.flatten(Set.of(1, 2)))                # => Set[1, 2]
```

## zip

`Set.zip(x, *Array)`

要素と各 Array の同じ位置の要素を組にした Tuple の Array。Array が短ければ nil が入ります。引数は Array でなければなりません（Set は静的に `type` の問題）。

```ruby
p(Set.zip(Set.of(1, 2, 3), Any["a", "b"]))   # => [[1, "a"], [2, "b"], [3, nil]]
p(Set.zip(Set.of(1, 2)))                       # => [[1], [2]]
```

## join

`Set.join(x, [String])`

要素を `to_s` でつなげた String。区切り（省略時 ""）を間に入れます。要素の Array は中まで開いてつなげます。

```ruby
s = Set.of(1, 2, 3)
p(Set.join(s))                    # => "123"
p(Set.join(s, ", "))              # => "1, 2, 3"
```

# Time

Time は 1 つの時刻です: 1970-01-01 00:00:00 UTC からの秒数（有理数の精度）と、表示に使う UTC からのオフセットを持ちます。リテラルは無く、`Time.now`、`Time.at(秒)`、`Time.new(年, 月, 日, ...)` で作ります（[値と型](../03-values.md)）。Ruby の Time と同じ値ですが、Ruby の `t.utc`、`t.localtime` が t 自身を書き換えるのに対し、Sake の操作はすべて新しい Time を返し、主語を変えません。Time に型付き Array `Time[]` は無く、Time の並びには `Any[...]` を使います。

**ゾーン。** `in:` キーワードと `getlocal`・`new` のゾーン引数は固定の UTC オフセットです: `"+09:00"`・`"-05:00"`、`"UTC"`・`"Z"`、軍用の 1 文字 `"A".."I"`, `"K".."Z"`、または秒数の Integer。`"Asia/Tokyo"` のような地域名は受け付けません（`ArgumentError`）。`in:` を省くと実行環境のローカルゾーンになるので、出力が環境に依らない例はすべて `in:` を付けています。`"UTC"`・`"Z"` で作った Time は UTC モード（`utc?` が true、`to_s` の末尾が `UTC`）で、`"+00:00"` はオフセット 0 の普通の Time です（`utc?` は false、末尾は `+0000`）。

Time に使える演算子は `+`、`-`（右が秒数の Integer・Float・Rational。`Time - Time` は秒数の Float）、`==`、`!=`、`<`、`<=`、`>`、`>=`、`<=>`（右は Time）です。下の `Time.+(x, y)` などはその関数形です（[演算子と添字](../05-operators.md)）。`Time.strftime(t, fmt)` と `Time.iso8601(t)` が文字列にします。String からの読み取り（Ruby の `Time.parse`、`Time.iso8601(s)`）は組み込みにはありません。

## now

`Time.now([in: String|Integer])`

今の時刻（Time）。`in:` を与えるとそのオフセットで表示される Time、省くとローカルゾーンです。不正なゾーンは `ArgumentError`。

```ruby
t = Time.now(in: "UTC")
p(Time.utc?(t))                        # => true
p(Time.year(t) >= 2026)                # => true
p(Time.utc_offset(Time.now(in: "+09:00")))   # => 32400
```

## at

`Time.at(Integer|Float|Rational|Time, [in: String|Integer])`

1970-01-01 00:00:00 UTC から `秒` 後の Time（Ruby の `Time.at`）。Integer、Float、Rational のどれでもよく、Rational なら精度が保たれます。Time を渡すと同じ時刻の Time です（`in:` が無ければゾーンも同じ）。`in:` でゾーンを選びます。不正なゾーンは `ArgumentError`。

```ruby
t = Time.at(0, in: "UTC")
p(t)                                   # => 1970-01-01 00:00:00 UTC
p(Time.at(1.5, in: "UTC"))             # => 1970-01-01 00:00:01.5 UTC
p(Time.subsec(Time.at(1r/3, in: "UTC")))   # => (1/3)
p(Time.at(t, in: "+09:00"))            # => 1970-01-01 09:00:00 +0900
p(Time.at(t) == t)                     # => true
```

```ruby error
Time.at(0, in: "Asia/Tokyo")           # !> ArgumentError: Time.at: "+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: Asia/Tokyo
```

## new

`Time.new(Integer, [Integer], [Integer], [Integer], [Integer], [Integer|Float|Rational], [String|Integer], [in: String|Integer])`

年・月・日・時・分・秒・ゾーンから Time を作ります（Ruby の `Time.new(y, m, d, h, min, s, zone)`）。年は必須で、残りは省けます（月と日は 1、時・分・秒は 0 が既定）。秒は Float か Rational で小数部を持てます。ゾーンは 7 番目の引数か `in:` のどちらか一方で（両方は `ArgumentError`）、無ければローカルゾーンです。月が 1..12、時が 0..23 などの範囲を外れると `ArgumentError`（`mon out of range`）。Ruby の引数無しの `Time.new`（今の時刻）はありません。`Time.now` を使います。

```ruby
t = Time.new(2024, 2, 29, 12, 30, 45, "+09:00")
puts(Time.to_s(t))                     # => 2024-02-29 12:30:45 +0900
puts(Time.to_s(Time.new(2024, in: "UTC")))         # => 2024-01-01 00:00:00 UTC
puts(Time.to_s(Time.new(2024, 3, 4, 5, in: "UTC")))   # => 2024-03-04 05:00:00 UTC
p(Time.subsec(Time.new(2024, 1, 1, 0, 0, 7.5, in: "Z")))   # => (1/2)
puts(Time.to_s(Time.new(2024, 3, 4, 5, 6, 7, 3600)))      # => 2024-03-04 05:06:07 +0100
```

```ruby error
Time.new(2024, 13, 1, in: "UTC")       # !> ArgumentError: Time.new: mon out of range
```

## year, month, mon, day, mday, hour, min, sec

`Time.year(x)`

`Time.month(x)`

`Time.mon(x)`

`Time.day(x)`

`Time.mday(x)`

`Time.hour(x)`

`Time.min(x)`

`Time.sec(x)`

時刻の各部分（Integer）を、その Time のオフソットで読みます: 年、月（1..12。`mon` は別名）、日（1..31。`mday` は別名）、時（0..23）、分（0..59）、秒（0..60。小数部は含みません。`subsec`）。

```ruby
t = Time.new(2024, 2, 29, 12, 30, 45.5, in: "+09:00")
p([Time.year(t), Time.month(t), Time.day(t)])      # => [2024, 2, 29]
p([Time.hour(t), Time.min(t), Time.sec(t)])        # => [12, 30, 45]
p(Time.mon(t) == Time.month(t))                    # => true
p(Time.hour(Time.utc(t)))                          # => 3
```

## wday, yday

`Time.wday(x)`

`Time.yday(x)`

曜日（Integer。日曜が 0、土曜が 6）と、年の中の日（1 月 1 日が 1、閏年の 12 月 31 日が 366）。

```ruby
t = Time.new(2024, 2, 29, in: "UTC")
p(Time.wday(t))                        # => 4
p(Time.yday(t))                        # => 60
p(Time.wday(Time.at(0, in: "UTC")))    # => 4
```

## sunday?, monday?, tuesday?, wednesday?, thursday?, friday?, saturday?

`Time.sunday?(x)`

`Time.monday?(x)`

`Time.tuesday?(x)`

`Time.wednesday?(x)`

`Time.thursday?(x)`

`Time.friday?(x)`

`Time.saturday?(x)`

その曜日なら true。`Time.wday(t) == 4` と `Time.thursday?(t)` は同じです。

```ruby
t = Time.new(2024, 2, 29, in: "UTC")
p(Time.thursday?(t))                   # => true
p(Time.friday?(t))                     # => false
p(Time.sunday?(t + 3 * 86400))         # => true
```

## nsec, usec, subsec, tv_sec, tv_nsec, tv_usec

`Time.nsec(x)`

`Time.usec(x)`

`Time.subsec(x)`

`Time.tv_sec(x)`

`Time.tv_nsec(x)`

`Time.tv_usec(x)`

秒より細かい部分。`nsec`（`tv_nsec` は別名）はナノ秒（Integer、0..999999999）、`usec`（`tv_usec` は別名）はマイクロ秒（Integer、0..999999）、`subsec` は秒の小数部をそのまま（Integer の 0、または Rational）。`tv_sec` は `to_i` と同じ、1970 年からの整数秒です。

```ruby
t = Time.at(1700000000.123456789r, in: "UTC")
p(Time.nsec(t))                        # => 123456789
p(Time.usec(t))                        # => 123456
p(Time.subsec(Time.at(1.5, in: "UTC")))    # => (1/2)
p(Time.subsec(Time.at(2, in: "UTC")))      # => 0
p(Time.tv_sec(t))                      # => 1700000000
p(Time.tv_nsec(t) == Time.nsec(t))     # => true
```

## to_i, to_f, to_r

`Time.to_i(x)`

`Time.to_f(x)`

`Time.to_r(x)`

1970-01-01 00:00:00 UTC からの秒数を、Integer（小数部は切り捨て）、Float、Rational（正確）で返します。ゾーンには依りません。`Time.at` の逆です。

```ruby
t = Time.at(1.5, in: "UTC")
p(Time.to_i(t))                        # => 1
p(Time.to_f(t))                        # => 1.5
p(Time.to_r(t))                        # => (3/2)
p(Time.to_i(Time.at(100, in: "+09:00")))   # => 100
```

## to_a

`Time.to_a(x)`

Ruby の `t.to_a`: `[sec, min, hour, day, month, year, wday, yday, isdst, zone]` の 10 要素の Tuple。最後の `zone` は `Time.zone` と同じで、UTC なら `"UTC"`、`in: "+09:00"` のような固定オフセットの Time では nil です。この要素の型は `String | nil` なので、確かめずに String として使うと `--strict`（レベル 2）が `nil` の問題として止めます。他の 9 つは Integer と Boolean です。

```ruby
p(Time.to_a(Time.at(0, in: "UTC")))        # => [0, 0, 0, 1, 1, 1970, 4, 1, false, "UTC"]
p(Time.to_a(Time.at(0, in: "+09:00")))     # => [0, 0, 9, 1, 1, 1970, 4, 1, false, nil]
sec, min, hour, day, month, year, wday, yday, isdst, zone = Time.to_a(Time.at(0, in: "UTC"))
p(zone ? String.size(zone) : 0)            # => 3
```

```ruby error
zone = Time.to_a(Time.at(0, in: "+09:00"))[9]
p(String.size(zone))                       # !> String.size: argument 1 may be nil
```

## to_s

`Time.to_s(x)`

`"2024-02-29 12:30:45 +0900"` の形の String（Ruby の `t.to_s`）。UTC モードの Time は末尾が `UTC`。小数部は書きません（`p(t)` と `inspect` は書きます）。`puts(t)` と `"#{t}"` もこの形です。

```ruby
t = Time.new(2024, 2, 29, 12, 30, 45.5, in: "+09:00")
puts(Time.to_s(t))                     # => 2024-02-29 12:30:45 +0900
puts(Time.utc(t))                      # => 2024-02-29 03:30:45 UTC
p(Time.at(0, in: "+00:00"))            # => 1970-01-01 00:00:00 +0000
```

## strftime

`Time.strftime(x, String)`

Ruby の `strftime` の書式で String を作ります: `%Y` 年、`%m` 月、`%d` 日、`%H`・`%M`・`%S` 時分秒、`%F`（`%Y-%m-%d`）、`%T`（`%H:%M:%S`）、`%z`（`+0900`）、`%:z`（`+09:00`）、`%Z`（ゾーン名。固定オフセットの Time では空）、`%A`・`%a` 曜日名、`%B`・`%b` 月名、`%j` 年の中の日、`%s` 1970 年からの秒、`%L` ミリ秒、`%N` ナノ秒（`%3N` で桁数）、`%-d` などの `-` は 0 埋めなし、`%%` は `%`。未知の指示子はそのまま残ります。

```ruby
t = Time.new(2024, 2, 29, 12, 30, 45, in: "+09:00")
puts(Time.strftime(t, "%Y-%m-%d %H:%M:%S %z"))   # => 2024-02-29 12:30:45 +0900
puts(Time.strftime(t, "%F %T %:z"))             # => 2024-02-29 12:30:45 +09:00
puts(Time.strftime(t, "%A %-d %B, day %j"))     # => Thursday 29 February, day 060
puts(Time.strftime(t, "%s|%L|%Z|%%"))           # => 1709177445|000||%
puts(Time.strftime(Time.utc(t), "%Z %z"))       # => UTC +0000
```

## iso8601

`Time.iso8601(x, [Integer])`

ISO 8601 の形 `2024-02-29T12:30:45+09:00` の String（Ruby の `t.iso8601`、`xmlschema`）。UTC モードの Time は末尾が `Z`。引数 `n` を与えると小数部を `n` 桁書きます（既定 0）。読み取り（Ruby のクラスメソッド `Time.iso8601(s)`）ではありません。

```ruby
t = Time.new(2024, 2, 29, 12, 30, 45.5, in: "+09:00")
puts(Time.iso8601(t))                  # => 2024-02-29T12:30:45+09:00
puts(Time.iso8601(t, 3))               # => 2024-02-29T12:30:45.500+09:00
puts(Time.iso8601(Time.utc(t)))        # => 2024-02-29T03:30:45Z
```

## asctime, ctime

`Time.asctime(x)`

`Time.ctime(x)`

C の `asctime` の形 `"Thu Feb 29 12:30:45 2024"`（Ruby の `t.asctime`、`t.ctime`。同じもの）。ゾーンは書きません。

```ruby
t = Time.new(2024, 2, 29, 12, 30, 45, in: "+09:00")
puts(Time.asctime(t))                  # => Thu Feb 29 12:30:45 2024
p(Time.ctime(t) == Time.asctime(t))    # => true
```

## utc, getutc, gmtime, getgm, gm

`Time.utc(Time|Integer, [Integer], [Integer], [Integer], [Integer], [Integer|Float|Rational])`

`Time.getutc(x)`

`Time.gmtime(x)`

`Time.getgm(x)`

`Time.gm(Integer, [Integer], [Integer], [Integer], [Integer], [Integer|Float|Rational])`

Time を渡すと、同じ時刻を UTC モードで表す新しい Time（Ruby の `t.getutc`）。4 つは同じもので、Ruby の `t.utc`・`t.gmtime` のように主語を書き換えることはありません。結果は `utc?` が true、`zone` が `"UTC"`、元の Time と `==` です。年（と、`new` と同じくその後の部分）を渡すと、`Time.utc` と `Time.gm` はその時刻を UTC で作ります（Ruby のクラスメソッド `Time.utc(y, m, d, h, min, s)` と `Time.gm`）。Time にさらに引数を付けると `ArgumentError` です。

```ruby
t = Time.new(2024, 2, 29, 12, 30, 45, in: "+09:00")
u = Time.utc(t)
puts(Time.to_s(u))                     # => 2024-02-29 03:30:45 UTC
puts(Time.to_s(t))                     # => 2024-02-29 12:30:45 +0900
p(Time.utc?(u))                        # => true
puts(Time.utc(2024, 2, 29, 3, 30, 45)) # => 2024-02-29 03:30:45 UTC
puts(Time.gm(2024))                    # => 2024-01-01 00:00:00 UTC
p(u == t)                              # => true
p(Time.getutc(t) == Time.gmtime(t) && Time.getgm(t) == u)   # => true
```

## localtime, getlocal

`Time.localtime(x, [String|Integer])`

`Time.getlocal(x, [String|Integer])`

同じ時刻を別のオフセットで表す新しい Time（Ruby の `t.getlocal(zone)`）。ゾーンは `"+09:00"`、`"UTC"`、秒数の Integer など（上記）。省くと実行環境のローカルゾーンです。2 つは同じもので、Ruby の `t.localtime` のように主語を書き換えることはありません。`"UTC"` を渡すと UTC モードになります。

```ruby
t = Time.at(1700000000, in: "+09:00")
puts(Time.to_s(Time.getlocal(t, "-05:00")))   # => 2023-11-14 17:13:20 -0500
puts(Time.to_s(Time.localtime(t, 3600)))      # => 2023-11-14 23:13:20 +0100
p(Time.utc?(Time.getlocal(t, "UTC")))         # => true
p(Time.getlocal(t) == t)                      # => true
puts(Time.to_s(t))                            # => 2023-11-15 07:13:20 +0900
```

## utc?, gmt?

`Time.utc?(x)`

`Time.gmt?(x)`

UTC モードの Time なら true（`"UTC"`・`"Z"` で作ったもの、`Time.utc` の結果）。オフセット 0 でも `"+00:00"` で作った Time は false です。`gmt?` は別名。

```ruby
p(Time.utc?(Time.at(0, in: "UTC")))    # => true
p(Time.utc?(Time.at(0, in: "+00:00"))) # => false
p(Time.gmt?(Time.utc(Time.at(0, in: "+09:00"))))   # => true
```

## zone

`Time.zone(x)`

ゾーンの名前（String）か nil。UTC モードなら `"UTC"`、ローカルゾーンの Time ならその略称（`"JST"` など、環境による）、`"+09:00"` のような固定オフセットで作った Time には名前が無いので nil です。戻り値は `String | nil` で、検査なしに String の操作に渡すと `--strict`（レベル 2）が止めます。オフセットが要るなら `utc_offset` を使います。

```ruby
p(Time.zone(Time.at(0, in: "UTC")))    # => "UTC"
p(Time.zone(Time.at(0, in: "+09:00"))) # => nil
```

## utc_offset, gmt_offset, gmtoff

`Time.utc_offset(x)`

`Time.gmt_offset(x)`

`Time.gmtoff(x)`

UTC からのオフセット（秒数の Integer。`+09:00` なら 32400、UTC なら 0）。3 つは別名です。

```ruby
t = Time.at(0, in: "+09:00")
p(Time.utc_offset(t))                  # => 32400
p(Time.gmt_offset(Time.at(0, in: "-05:00")))   # => -18000
p(Time.gmtoff(Time.utc(t)))            # => 0
```

## dst?, isdst

`Time.dst?(x)`

`Time.isdst(x)`

夏時間の中なら true（Ruby の `t.dst?`）。固定オフセットと UTC の Time では常に false で、true になりうるのはローカルゾーンの Time だけです。`isdst` は別名。

```ruby
p(Time.dst?(Time.at(0, in: "UTC")))    # => false
p(Time.isdst(Time.at(0, in: "+09:00")))    # => false
```

## round, floor, ceil

`Time.round(x, [Integer])`

`Time.floor(x, [Integer])`

`Time.ceil(x, [Integer])`

秒の小数部を `n` 桁（既定 0）に丸めた新しい Time（Ruby の `t.round(n)`）。`round` は四捨五入、`floor` は切り捨て、`ceil` は切り上げ。負の `n` は `ArgumentError`。

```ruby
t = Time.at(1700000000.123456789r, in: "UTC")
puts(Time.iso8601(Time.round(t, 2), 9))    # => 2023-11-14T22:13:20.120000000Z
puts(Time.iso8601(Time.floor(t, 1), 9))    # => 2023-11-14T22:13:20.100000000Z
puts(Time.iso8601(Time.ceil(t), 9))        # => 2023-11-14T22:13:21.000000000Z
p(Time.round(Time.at(1.5, in: "UTC")) == Time.at(2, in: "UTC"))   # => true
```

## +, -

`Time.+(x, Any)`

`Time.-(x, Any)`

`t + 秒` と `t - 秒` は秒数（Integer、Float、Rational）だけ後・前の新しい Time で、ゾーンは t のものです。`t1 - t2` は 2 つの Time の差の秒数を Float で返します。`Time + Time` と、秒数でない右辺は静的に `type` の問題です。日や月の単位は無いので、1 日は `86400` と書きます。

```ruby
a = Time.at(100, in: "UTC")
p(a + 5)                               # => 1970-01-01 00:01:45 UTC
p(a - 1.5)                             # => 1970-01-01 00:01:38.5 UTC
p((a + 5) - a)                         # => 5.0
p(a - (a + 5))                         # => -5.0
p(Time.-(a, 1r/4) == Time.at(99.75, in: "UTC"))   # => true
d = Time.new(2024, 3, 10, in: "UTC") - Time.new(2024, 1, 1, in: "UTC")
p(Integer(d / 86400))                  # => 69
```

```ruby error
a = Time.at(0, in: "UTC")
p(a + a)                               # !> the operands are (Time, Time), which the left operand's type does not support
```

## ==, !=

`Time.==(x, Any)`

`Time.!=(x, Any)`

同じ時刻なら true（`!=` はその否定）。ゾーンは比べないので、`Time.at(100, in: "UTC")` と `Time.at(100, in: "+09:00")` は等しいです。右が Time でない値（nil、Integer など）なら `==` は false、`!=` は true で、演算子の形 `t == v` も関数の形 `Time.==(t, v)` も同じです。関数の形はどんな値も受け取り、例外にはなりません。

```ruby
a = Time.at(100, in: "UTC")
p(a == Time.at(100, in: "+09:00"))     # => true
p(a != a + 1)                          # => true
p(a == nil)                            # => false
p(Time.==(a, Time.at(100.0, in: "UTC")))   # => true
p(Time.==(a, 100))                     # => false
p(Time.!=(a, 100))                     # => true
```

## <, <=, >, >=

`Time.<(x, Any)`

`Time.<=(x, Any)`

`Time.>(x, Any)`

`Time.>=(x, Any)`

時刻の前後で比べます（早い方が小さい）。右は Time でなければならず、Integer などは関数の形 `Time.<(t, 100)` でも静的に `type` の問題です（false を返すだけの `==` とは違います）。

```ruby
a = Time.at(100, in: "UTC")
b = a + 5
p(a < b)                               # => true
p(a <= a)                              # => true
p(b > a && b >= a)                     # => true
p(Time.<(b, a))                        # => false
```

```ruby error
a = Time.at(100, in: "UTC")
p(a < 100)                             # !> the operands are (Time, Integer), which the left operand's type does not support
```

## <=>

`Time.<=>(x, Any)`

前後の比較の結果を -1、0、1 で返します（Integer。Time どうしは常に比べられるので nil にはなりません）。`Array.sort` と `Array.sort_by` のキーに Time を使うと時刻順に並びます。

```ruby
a = Time.at(100, in: "UTC")
p(a <=> a + 1)                         # => -1
p(a <=> a)                             # => 0
p(Time.<=>(a + 1, a))                  # => 1
xs = Array.sort(Any[a + 9, a, a + 3])
p(Array.map(xs) { |t| Time.to_i(t) })  # => [100, 103, 109]
```

# IO

IO は開いたファイルとプログラムの標準ストリームの型です。値は操作から来ます: `IO.stdin`、`IO.stdout`、`IO.stderr` が標準ストリームを、`File.open(path, mode)` がファイルを与えます（Sake に `$stdout` や `STDOUT` はありません。[値と型](../03-values.md)）。ファイルとストリームの型は 1 つなので、IO を受け取る関数はどちらにも書けます。IO のリテラルはありません。

Ruby の `io.puts(x)` は `IO.puts(io, x)` と書きます。Ruby の `IO` のメソッドのうち、ここに挙げたものだけがあります。読み書きの失敗（閉じた IO、その向きに開いていない IO、OS のエラー）は `IOError` です（Ruby の `Errno::ENOENT` などもまとめて `IOError`。[例外](../08-exceptions.md)）。

IO に使える演算子は `==`、`!=` だけです（同じストリームか同じ `File.open` の結果のとき等しい）。引数の無い操作 `IO.stdout()` は `IO.stdout` とも書けます。

## stdin, stdout, stderr

`IO.stdin()`

`IO.stdout()`

`IO.stderr()`

プログラムの標準入力・標準出力・標準エラー出力を IO として返します。何度呼んでも同じ値で、`IO.stdout == IO.stdout` は true です。`Kernel.puts` と `Kernel.p` は `IO.stdout` に書き、`Kernel.gets` は `IO.stdin` から読みます。`IO.stderr` への書き込みは先に stdout を flush するので、2 つのストリームの行の順序が保たれます。標準ストリームを `IO.close` で閉じることはできますが、役に立つ場面はほとんどありません: 閉じた後はそこへの書き込み（`p`、`puts`、`IO.write`）がすべて `IOError`（`closed stream`）になります。rescue でき、`IO.stderr` はそのまま使えます。

```ruby
out = IO.stdout
IO.puts(out, "hello")            # => hello
p(IO.stdout == out)              # => true
p(IO.stdout == IO.stderr)        # => false
p(IO.stdin)                      # => #<IO:<STDIN>>
```

```ruby error
IO.close(IO.stdout)
puts("x")                        # !> IOError: Kernel.puts: closed stream
```

## puts

`IO.puts(x, *Any)`

各引数を `Kernel.puts` と同じ形で `x` に書き、nil を返します。引数ごとに 1 行（末尾に改行が無ければ加える）。Array と Tuple は平らにして要素ごとに 1 行、空の Array は空行、引数が無ければ空行 1 つ。文字列以外は `Kernel.to_s` の形です（nil は空行、Symbol は名前）。閉じた IO や読み出し専用の IO には `IOError`。

```ruby
out = IO.stdout
IO.puts(out, "a", 1)             # => a
                                 # => 1
IO.puts(out, [1, Any[2, 3]])   # => 1
                                 # => 2
                                 # => 3
IO.puts(out, "x\n")              # => x
p(IO.puts(out, :s))              # => s
                                 # => nil
```

## print

`IO.print(x, *Any)`

各引数の `to_s` を改行を挟まずに `x` に書き、nil を返します（Ruby の `io.print`）。Array は `[1, 2]` の形、nil は空文字列です。

```ruby
out = IO.stdout
IO.print(out, "a", 1, :s, "\n")  # => a1s
IO.print(out, Any[1, 2], "\n") # => [1, 2]
```

## write

`IO.write(x, String)`

文字列をそのまま `x` に書き、書いたバイト数（Integer）を返します。改行は加えません。引数は String でなければならず、他の型は静的に `type` の問題です（`puts` や `print` と違い、変換しません）。

```ruby
p(IO.write(IO.stdout, "ab\n"))   # => ab
                                 # => 3
p(IO.write(IO.stdout, "日本\n")) # => 日本
                                 # => 7
```

```ruby error
IO.write(IO.stdout, 1)           # !> IO.write: argument 2 must be String, but is Integer
```

## flush

`IO.flush(x)`

バッファに溜まった出力を書き出し、`x` を返します。`File.open` で開いたファイルへの `IO.write` や `IO.puts` はバッファされ、`flush` か `close` でファイルに届きます。

```ruby
f = File.open("log.txt", "w")
IO.puts(f, "a")
p(File.read("log.txt"))          # => ""
IO.flush(f)
p(File.read("log.txt"))          # => "a\n"
IO.close(f)
```

## gets

`IO.gets(x)`

次の 1 行を改行を含めて返し（Ruby の `io.gets`）、終端では nil です。結果は `String | nil` なので、`--strict`（レベル 2）はそのまま使うことを `nil` の問題として報告します: `if line`、`while (line = IO.gets(io))` のように確かめてから使います。書き込み専用の IO では `IOError`。

```ruby
io = IO.stdin
line = IO.gets(io)
if line
  p(String.to_i(line))           # => 3
end
while (l = IO.gets(io))
  p(l)                           # => "1 2\n"
end
p(IO.gets(io))                   # => nil
```

```ruby error
line = IO.gets(IO.stdin)
p(String.upcase(line))           # !> argument 1 may be nil
```

## read

`IO.read(x, [Integer])`

`IO.read(io)` は現在位置から終端までをすべて読んで String を返します（終端ではすでに空文字列 `""`。nil にはなりません）。`IO.read(io, n)` は最大 `n` バイト（文字ではなくバイト）を読み、終端に達していれば nil を返します（`n` が 0 のときは常に `""`）。この 2 引数の形だけが `String | nil` で、レベル 2 で検査されます。読み出しに開いていない IO は `IOError`。

```ruby
io = IO.stdin
p(IO.read(io, 2))                # => "3\n"
p(IO.read(io))                   # => "1 2\n"
p(IO.read(io))                   # => ""
p(IO.read(io, 1))                # => nil
```

## getc

`IO.getc(x)`

次の 1 文字を String で返し、終端では nil です（`String | nil`、レベル 2）。

```ruby
io = IO.stdin
p(IO.getc(io))                   # => "3"
p(IO.getc(io))                   # => "\n"
IO.read(io)
p(IO.getc(io))                   # => nil
```

## readlines

`IO.readlines(x)`

現在位置から終端までを行に分けて、String の Array で返します（各行は改行を含みます）。終端では空の Array です。

```ruby
p(IO.readlines(IO.stdin))        # => ["3\n", "1 2\n"]
p(IO.readlines(IO.stdin))        # => []
```

## each_line

`IO.each_line(x) { }`

現在位置から終端まで、1 行ずつ（改行を含む String）ブロックに渡し、`x` を返します。ブロックの値は使いません。Ruby の `io.each_line` と同じで、ブロックは必須です。

```ruby
r = IO.each_line(IO.stdin) { |l| p(String.chomp(l)) }   # => "3"
                                                         # => "1 2"
p(r == IO.stdin)                 # => true
```

## eof?

`IO.eof?(x)`

読み出し位置が終端にあれば true。書き込み専用の IO や閉じた IO では `IOError`。

```ruby
io = IO.stdin
p(IO.eof?(io))                   # => false
IO.read(io)
p(IO.eof?(io))                   # => true
```

## seek

`IO.seek(x, Integer, [Integer|Symbol])`

読み書きの位置を動かし、0 を返します（Ruby の `io.seek`）。第 2 引数はオフセット、第 3 引数は基準で、省略すると先頭（`0`）。`0`/`:SET` は先頭から、`1`/`:CUR` は現在位置から、`2`/`:END` は末尾から（オフセットは負）。Symbol はこの 3 つだけで、他の Symbol は `ArgumentError` です。seek できないストリーム（パイプの `IO.stdin` など）は `IOError`。

```ruby
File.write("a.txt", "hello\n")
f = File.open("a.txt")
IO.seek(f, 2)
p(IO.read(f, 2))                 # => "ll"
IO.seek(f, -2, :END)
p(IO.read(f))                    # => "o\n"
p(IO.seek(f, 1, :SET))           # => 0
p(IO.getc(f))                    # => "e"
IO.close(f)
```

```ruby error
File.write("a.txt", "hello\n")
f = File.open("a.txt")
IO.seek(f, 1, :FOO)              # !> ArgumentError: IO.seek: unknown whence: :FOO (0/1/2 or :SET/:CUR/:END)
```

## pos

`IO.pos(x)`

現在の位置（先頭からのバイト数、Integer）。seek できないストリームでは `IOError`。

```ruby
File.write("a.txt", "日本\n")
f = File.open("a.txt")
p(IO.pos(f))                     # => 0
IO.getc(f)
p(IO.pos(f))                     # => 3
IO.close(f)
```

## rewind

`IO.rewind(x)`

位置を先頭に戻し、0 を返します。もう一度読み直すときに使います。

```ruby
File.write("a.txt", "one\n")
f = File.open("a.txt")
p(IO.gets(f))                    # => "one\n"
p(IO.rewind(f))                  # => 0
p(IO.gets(f))                    # => "one\n"
IO.close(f)
```

## size

`IO.size(x)`

開いたファイルの大きさ（バイト数、Integer）。まだ flush していない書き込みも含みます。ファイルでない IO（`IO.stdin` などのストリーム）は `IOError`（`not a file`）です。

```ruby
f = File.open("a.txt", "w")
IO.write(f, "abc")
p(IO.size(f))                    # => 3
IO.close(f)
```

```ruby error
IO.size(IO.stdin)                # !> IOError: IO.size: not a file
```

## truncate

`IO.truncate(x, Integer)`

ファイルを `n` バイトに切り詰め、0 を返します。書き込みに開いていないファイルは `IOError`。

```ruby
File.write("a.txt", "hello")
r = File.open("a.txt", "r+") { |f| IO.truncate(f, 3) }
p(r)                             # => 0
p(File.read("a.txt"))            # => "hel"
```

```ruby error
File.write("a.txt", "hello")
f = File.open("a.txt")
IO.truncate(f, 1)                # !> IOError: IO.truncate: not opened for writing
```

## close

`IO.close(x)`

IO を閉じて nil を返します。バッファの出力は書き出されます。閉じた IO をもう一度閉じても何も起きません（Ruby と同じ）。閉じた IO への読み書きは `IOError`。`File.open` のブロック形はブロックの後に自動で閉じるので、`close` は手で開いたときだけ必要です。

```ruby
f = File.open("a.txt", "w")
IO.write(f, "x")
p(IO.close(f))                   # => nil
p(IO.close(f))                   # => nil
p(File.read("a.txt"))            # => "x"
```

```ruby error
f = File.open("a.txt", "w")
IO.close(f)
IO.write(f, "x")                 # !> IOError: IO.write: closed stream
```

## closed?

`IO.closed?(x)`

閉じていれば true。`File.open` のブロックに渡された IO は、ブロックの後では閉じています。

```ruby
kept = IO.stdout
File.open("a.txt", "w") { |f| kept = f }
p(IO.closed?(kept))              # => true
p(IO.closed?(IO.stdout))         # => false
```

## tty?

`IO.tty?(x)`

端末に繋がっていれば true（Ruby の `io.tty?`）。ファイルやパイプでは false。検査器の中では標準入出力もパイプなので false です。以下の端末の操作（`winsize`、`raw`、`noecho`、`getch`）はこれが true のときだけ使えます。

```ruby
f = File.open("a.txt", "w")
p(IO.tty?(f))                    # => false
IO.close(f)
```

## winsize

`IO.winsize(x)`

`x` が繋がっている端末の大きさを Tuple `[rows, columns]`（Integer, Integer）で返します（Ruby の `io/console` の `io.winsize`）。`rows, cols = IO.winsize(IO.stdout)` と多重代入で受けます。端末でない IO（ファイル、パイプ、検査器の中の標準ストリーム）は `IOError`（`not a terminal`）。端末では:

```
rows, cols = IO.winsize(IO.stdout)
p([rows, cols])                  # 80x24 の端末なら [24, 80]
```

検査器の中では stdin がパイプなので、示せるのはエラーだけです:

```ruby
begin
  IO.winsize(IO.stdin)
rescue IOError => e
  p(Exception.message(e))        # => "not a terminal"
end
```

## raw, noecho

`IO.raw(x) { }`

`IO.noecho(x) { }`

`x` の端末を raw モード（`raw`: キーが行の終わりを待たずに 1 つずつ届き、エコーされない）またはエコー無し（`noecho`: 行単位の読み出しのまま、打った文字が表示されない）にしてブロックを走らせ、終わると（例外で抜けても）端末を元に戻し、ブロックの値を返します（Ruby の `io.raw { }`、`io.noecho { }`）。結果の型はブロックの型です。ブロックは必須で、引数は受け取りません。端末でない IO は `IOError`（`not a terminal`）。端末では、パスワードを表示せずに読む・Enter を待たずに 1 キー読む、と使います:

```
pw = IO.noecho(IO.stdin) { IO.gets(IO.stdin) }   # secret と Enter を打つと "secret\n"
k = IO.raw(IO.stdin) { IO.getch(IO.stdin) }      # x を押した瞬間に "x"
```

```ruby
begin
  IO.noecho(IO.stdin) { IO.gets(IO.stdin) }
rescue IOError => e
  p(Exception.message(e))        # => "not a terminal"
end
```

## getch

`IO.getch(x)`

`x` の端末からキーを 1 つ読み、Enter を待たず・エコーせずに String で返します（Ruby の `io.getch`）。結果は `String | nil`（入力の終端で nil）なので、`--strict`（レベル 2）はそのまま使うことを `nil` の問題として報告します。端末でない IO は `IOError`（`not a terminal`）。パイプやファイルから 1 文字読むには `IO.getc` を使います。端末では:

```
k = IO.getch(IO.stdin)           # y を押した瞬間に "y"
```

```ruby
begin
  IO.getch(IO.stdin)
rescue IOError => e
  p(Exception.message(e))        # => "not a terminal"
end
```

## ==, !=

`IO.==(x, Any)`

`IO.!=(x, Any)`

2 つの IO 値が同じストリーム、または同じ `File.open` の結果なら等しい（`!=` はその否定）。同じパスを 2 回開いた IO は別の値です。IO 以外の値とは等しくありません。

```ruby
f = File.open("a.txt", "w")
g = File.open("a.txt", "w")
p(f == f)                        # => true
p(f == g)                        # => false
p(IO.stdout != IO.stdin)         # => true
IO.close(f)
IO.close(g)
```

# File

File はファイルをパス（String）で扱う操作の集まりです。File という型の値はありません: `File.open` が返すのは `IO`（[IO](IO.md)）で、他の操作はパスを受け取ってその場で読み書き・問い合わせをします。Ruby の `File.read(path)` などのクラスメソッドと同じ名前で、インスタンスメソッド（`file.read`）に当たるものは `IO` の操作です（[値と型](../03-values.md)、[組み込み](../09-builtins.md)）。

システムコールの失敗（無いパス、権限、ディレクトリを読む、など。Ruby では `Errno::ENOENT` などの例外）はすべて `IOError` で、メッセージは Ruby のものです（[例外](../08-exceptions.md)）。パスの文字列処理（`basename`、`join`、`expand_path` など）はファイルを見ません。`exist?` などの問い合わせは失敗せず false を返します。

File に演算子はありません。例は空のディレクトリで実行され、そこにファイルを作ります。

## open

`File.open(String, [String], [Integer]) [{ }]`

ファイルを開いて `IO` を返します。第 2 引数はモードで省略すると `"r"`（Ruby と同じ: `"r"` 読む、`"w"` 書く（空にする）、`"a"` 追記、`"r+"` 読み書き、`"w+"`、`"a+"`、`"b"` を付けるとバイナリ）。第 3 引数は新しく作るファイルの許可ビット（`0o600` など。既にあるファイルには影響しません）。ブロックを付けると `IO` をブロックに渡し、ブロックの後にファイルを閉じて**ブロックの値**を返します（Ruby と同じ）。ブロック無しなら `IO.close` で自分で閉じます。無いファイルや権限の無いファイルは `IOError`、知らないモードは `ArgumentError`。

```ruby
f = File.open("a.txt", "w")
IO.puts(f, "one")
IO.close(f)
n = File.open("a.txt", "a") { |io| IO.write(io, "two\n") }
p(n)                                # => 4
p(File.open("a.txt") { |io| IO.readlines(io) })   # => ["one\n", "two\n"]
File.open("p.txt", "w", 0o600) { |io| nil }
p(File.exist?("p.txt"))             # => true
```

```ruby error
File.open("nope.txt")               # !> IOError: File.open: No such file or directory
```

## read

`File.read(String)`

ファイル全体を String で返します。無いファイルやディレクトリは `IOError`。

```ruby
File.write("a.txt", "hello\n")
p(File.read("a.txt"))               # => "hello\n"
```

```ruby error
File.read("nope.txt")               # !> IOError: File.read: No such file or directory
```

## readlines

`File.readlines(String)`

ファイル全体を行に分けた String の Array（各行は改行を含みます）。空のファイルは空の Array。

```ruby
File.write("a.txt", "a\nb\n")
p(File.readlines("a.txt"))          # => ["a\n", "b\n"]
```

## write

`File.write(String, String)`

ファイルを作る（あれば中身を置き換える）か書き、書いたバイト数（Integer）を返します。追記はしません（追記は `File.open(path, "a")`）。第 2 引数は String だけで、他の型は静的に `type` の問題です。

```ruby
p(File.write("a.txt", "日本"))      # => 6
p(File.write("a.txt", "x"))         # => 1
p(File.read("a.txt"))               # => "x"
```

```ruby error
File.write("a.txt", 1)              # !> File.write: argument 2 must be String, but is Integer
```

## exist?

`File.exist?(String)`

パスにファイルかディレクトリがあれば true。失敗しません。

```ruby
File.write("a.txt", "")
p(File.exist?("a.txt"))             # => true
p(File.exist?("."))                 # => true
p(File.exist?("nope"))              # => false
```

## file?, directory?, symlink?

`File.file?(String)`

`File.directory?(String)`

`File.symlink?(String)`

通常のファイル・ディレクトリ・シンボリックリンクなら true。`file?` と `directory?` はリンクをたどって先を見ます。無いパスは false。

```ruby
File.write("a.txt", "")
File.symlink("a.txt", "l1.txt")
p(File.file?("a.txt"))              # => true
p(File.file?("."))                  # => false
p(File.directory?("."))             # => true
p(File.symlink?("l1.txt"))           # => true
p(File.symlink?("a.txt"))           # => false
p(File.file?("nope"))               # => false
```

## zero?, empty?

`File.zero?(String)`

`File.empty?(String)`

ファイルがあって大きさが 0 なら true（2 つは同じ。Ruby と同じ）。無いパスは false。

```ruby
File.write("e.txt", "")
File.write("a.txt", "x")
p(File.zero?("e.txt"))              # => true
p(File.empty?("a.txt"))             # => false
p(File.zero?("nope"))               # => false
```

## readable?, writable?, executable?

`File.readable?(String)`

`File.writable?(String)`

`File.executable?(String)`

このプロセスがそのパスを読める・書ける・実行できるなら true。無いパスは false。

```ruby
File.write("a.txt", "")
p(File.readable?("a.txt"))          # => true
p(File.writable?("a.txt"))          # => true
p(File.executable?("a.txt"))        # => false
File.chmod(0o755, "a.txt")
p(File.executable?("a.txt"))        # => true
```

## size

`File.size(String)`

ファイルの大きさ（バイト数、Integer）。無いパスは `IOError`。

```ruby
File.write("a.txt", "日本")
p(File.size("a.txt"))               # => 6
```

```ruby error
File.size("nope")                   # !> IOError: File.size: No such file or directory
```

## mtime, atime

`File.mtime(String)`

`File.atime(String)`

最後に変更された・読まれた時刻を Time で返します。無いパスは `IOError`。

```ruby
File.write("a.txt", "")
File.utime(Time.at(0), Time.at(60), "a.txt")
p(Time.to_i(File.atime("a.txt")))   # => 0
p(Time.to_i(File.mtime("a.txt")))   # => 60
p(File.mtime("a.txt") <= Time.now)  # => true
```

## ftype

`File.ftype(String)`

種類を String で返します: `"file"`、`"directory"`、`"link"`（リンクそのもの。たどりません）、`"characterSpecial"` など Ruby と同じ。無いパスは `IOError`。

```ruby
File.write("a.txt", "")
File.symlink("a.txt", "l2.txt")
p(File.ftype("a.txt"))              # => "file"
p(File.ftype("."))                  # => "directory"
p(File.ftype("l2.txt"))              # => "link"
```

## identical?

`File.identical?(String, String)`

2 つのパスが同じファイルを指すなら true（リンクをたどります。ハードリンクも同じ）。どちらかが無ければ false。

```ruby
File.write("a.txt", "")
File.write("b.txt", "")
File.symlink("a.txt", "l3.txt")
p(File.identical?("a.txt", "l3.txt"))   # => true
p(File.identical?("a.txt", "b.txt"))   # => false
p(File.identical?("a.txt", "nope"))    # => false
```

## rename

`File.rename(String, String)`

ファイルを移す（名前を変える）。0 を返します。移す先にファイルがあれば置き換えます。元が無ければ `IOError`。

```ruby
File.write("a.txt", "x")
p(File.rename("a.txt", "b.txt"))    # => 0
p(File.exist?("a.txt"))             # => false
p(File.read("b.txt"))               # => "x"
```

```ruby error
File.rename("nope", "b.txt")        # !> IOError: File.rename: No such file or directory
```

## delete, unlink

`File.delete(String)`

`File.unlink(String, *String)`

ファイルを消します。`delete` は 1 つのパスを取り 1 を返します。`unlink` は 1 つ以上のパスを取り、消した数（Integer）を返します。ディレクトリは消せません（`Dir.rmdir`）。無いパスは `IOError`（Ruby の `Errno::ENOENT`）。

```ruby
File.write("a.txt", "")
File.write("b.txt", "")
File.write("c.txt", "")
p(File.delete("a.txt"))             # => 1
p(File.unlink("b.txt", "c.txt"))    # => 2
p(File.exist?("c.txt"))             # => false
```

```ruby error
File.delete("nope")                 # !> IOError: File.delete: No such file or directory
```

## symlink, link

`File.symlink(String, String)`

`File.link(String, String)`

`symlink(target, link)` はシンボリックリンク、`link(target, link)` はハードリンクを作り、0 を返します。`link` 側が既にあれば `IOError`。

```ruby
File.write("a.txt", "x")
p(File.symlink("a.txt", "s.txt"))   # => 0
p(File.link("a.txt", "h.txt"))      # => 0
p(File.read("s.txt"))               # => "x"
p(File.symlink?("h.txt"))           # => false
p(File.identical?("a.txt", "h.txt"))   # => true
```

```ruby error
File.write("a.txt", "")
File.symlink("a.txt", "a.txt")      # !> IOError: File.symlink: File exists
```

## readlink

`File.readlink(String)`

シンボリックリンクが指すパスを String で返します（書かれたままで、解決はしません）。リンクでないパスは `IOError`。

```ruby
File.write("a.txt", "")
File.symlink("a.txt", "l4.txt")
p(File.readlink("l4.txt"))           # => "a.txt"
```

```ruby error
File.write("a.txt", "")
File.readlink("a.txt")              # !> IOError: File.readlink: Invalid argument
```

## chmod

`File.chmod(Integer, *String)`

許可ビットを `mode`（`0o644` など）に変え、変えたファイルの数を返します。パスが無ければ 0。無いパスは `IOError`。

```ruby
File.write("a.txt", "")
File.write("b.sh", "")
p(File.chmod(0o755, "a.txt", "b.sh"))   # => 2
p(File.executable?("b.sh"))         # => true
p(File.chmod(0o644))                # => 0
```

## utime

`File.utime(Time|Nil, Time|Nil, *String)`

`utime(atime, mtime, *paths)`: 読まれた時刻と変更された時刻を設定し、変えたファイルの数を返します。nil は現在時刻です。無いパスは `IOError`。

```ruby
File.write("a.txt", "")
p(File.utime(Time.at(10), Time.at(20), "a.txt"))   # => 1
p(Time.to_i(File.atime("a.txt")))   # => 10
p(Time.to_i(File.mtime("a.txt")))   # => 20
File.utime(nil, nil, "a.txt")
p(File.mtime("a.txt") > Time.at(20))   # => true
```

## basename

`File.basename(String, [String])`

パスの最後の要素。第 2 引数に拡張子（`".rb"`）を与えるとそれを取り、`".*"` ならどんな拡張子でも取ります。ファイルは見ません。

```ruby
p(File.basename("/a/b/c.rb"))       # => "c.rb"
p(File.basename("/a/b/c.rb", ".rb"))   # => "c"
p(File.basename("c.tar.gz", ".*"))  # => "c.tar"
p(File.basename("/a/b/"))           # => "b"
```

## dirname

`File.dirname(String, [Integer])`

最後の要素を取ったディレクトリ部分。第 2 引数 `n` で `n` 段上がります（省略時 1、0 なら元のまま）。ディレクトリ部分が無ければ `"."`。

```ruby
p(File.dirname("/a/b/c.rb"))        # => "/a/b"
p(File.dirname("/a/b/c.rb", 2))     # => "/a"
p(File.dirname("c.rb"))             # => "."
```

## extname

`File.extname(String)`

最後の要素の拡張子（ドットを含む）。無ければ `""`。ドットで始まる名前（`.bashrc`）は拡張子無しです。

```ruby
p(File.extname("c.tar.gz"))         # => ".gz"
p(File.extname("c"))                # => ""
p(File.extname(".bashrc"))          # => ""
```

## split

`File.split(String)`

`[dirname, basename]` の 2 要素の Tuple（String, String）。Ruby では Array ですが Sake では Tuple で、`dir, base = File.split(p)` で分解します。

```ruby
dir, base = File.split("/a/b/c.rb")
p(dir)                              # => "/a/b"
p(base)                             # => "c.rb"
p(File.split("c.rb"))               # => [".", "c.rb"]
```

## join

`File.join(*String|Array)`

部分を `/` で繋いだパス。重なる `/` は 1 つにします。引数は String か String の Array（入れ子も平らにします）で、引数が無ければ `""`。他の型は静的に `type` の問題です。

```ruby
p(File.join("a", "b", "c.rb"))      # => "a/b/c.rb"
p(File.join("a/", "/b"))            # => "a/b"
p(File.join(Any["a", "b"], "c"))  # => "a/b/c"
p(File.join())                      # => ""
```

```ruby error
File.join(1)                        # !> File.join: argument 1 must be String|Array, but is Integer
```

## expand_path, absolute_path

`File.expand_path(String, [String])`

`File.absolute_path(String, [String])`

相対パスを絶対パスにします。第 2 引数は基準のディレクトリで、省略すると現在のディレクトリ（`Dir.pwd`）。`.` と `..` は解決しますが、ファイルは見ずリンクもたどりません。違いは `~`: `expand_path` は `~` をホームディレクトリに展開し（知らないユーザーの `~user` は `ArgumentError`）、`absolute_path` は展開しません（Ruby と同じ）。

```ruby
p(File.expand_path("/x/../y"))      # => "/y"
p(File.expand_path("b", "/a"))      # => "/a/b"
p(File.absolute_path("b", "/a"))    # => "/a/b"
p(File.expand_path("a") == File.join(Dir.pwd, "a"))   # => true
p(File.expand_path("~") == Dir.home)                  # => true
p(File.absolute_path("~") == File.join(Dir.pwd, "~")) # => true
```

## absolute_path?

`File.absolute_path?(String)`

パスが絶対（`/` で始まる）なら true。ファイルは見ません。

```ruby
p(File.absolute_path?("/a/b"))      # => true
p(File.absolute_path?("a/b"))       # => false
```

## realpath

`File.realpath(String, [String])`

シンボリックリンクをすべてたどった実際の絶対パス。第 2 引数は相対パスの基準ディレクトリです。パスは実在しなければならず、無ければ `IOError`（`expand_path` との違い）。

```ruby
File.write("a.txt", "")
File.symlink("a.txt", "l5.txt")
p(File.realpath("l5.txt") == File.join(Dir.pwd, "a.txt"))   # => true
p(File.realpath("l5.txt", Dir.pwd) == File.realpath("./a.txt"))   # => true
```

```ruby error
File.realpath("nope")               # !> IOError: File.realpath: No such file or directory
```

# Dir

Dir はディレクトリをパス（String）で扱う操作の集まりです。Dir という型の値はなく（Ruby の `Dir.open` や `Dir` オブジェクトはありません）、すべて Ruby の `Dir` のクラスメソッドと同じ名前・同じ結果です（[組み込み](../09-builtins.md)）。中身の一覧は String の Array で返ります。

システムコールの失敗（無いディレクトリ、空でないディレクトリの削除、など。Ruby の `Errno::ENOENT` 等）はすべて `IOError` で、メッセージは Ruby のものです（[例外](../08-exceptions.md)）。`exist?` は失敗せず false、`glob` は何にも合わなければ空の Array です。

Dir に演算子はありません。例は空のディレクトリで実行され、そこにディレクトリを作ります。

## children, entries

`Dir.children(String)`

`Dir.entries(String)`

ディレクトリの中の名前（パスではなく名前だけ）の Array。`children` は `.` と `..` を含まず、`entries` は含みます。順序は OS が返す順で決まっていないので、並べて使うなら `Array.sort`。無いディレクトリは `IOError`。

```ruby
Dir.mkdir("d1")
File.write("d1/a.txt", "")
File.write("d1/b.rb", "")
p(Array.sort(Dir.children("d1")))   # => ["a.txt", "b.rb"]
p(Array.sort(Dir.entries("d1")))    # => [".", "..", "a.txt", "b.rb"]
```

```ruby error
Dir.children("nope")                # !> IOError: Dir.children: No such file or directory
```

## each_child

`Dir.each_child(String) { }`

`children` の各名前を順にブロックに渡し、nil を返します（Ruby は Dir を返しますが、Sake では nil）。ブロックの値は使いません。順序は `children` と同じく決まっていません。無いディレクトリは `IOError`。

```ruby
Dir.mkdir("d2")
File.write("d2/x", "")
File.write("d2/y", "")
names = Any[]
r = Dir.each_child("d2") { |n| Array.push(names, n) }
p(Array.sort(names))                # => ["x", "y"]
p(r)                                # => nil
```

## glob

`Dir.glob(String|Array, [base: String])`

パターンに合うパスの Array（Ruby の `Dir.glob`。`*`、`?`、`[...]`、`{a,b}`、`**/` が使えます）。パターンは String か String の Array（どれかに合えばよい）。結果は Ruby と同じく並べ替え済みで、ドットで始まる名前は `*` に合いません。キーワード `base:` を与えると、そのディレクトリから探して**相対の名前**を返します。合うものが無いときや `base:` のディレクトリが無いときは空の Array で、失敗しません。

```ruby
Dir.mkdir("d3")
File.write("d3/a.txt", "")
File.write("d3/b.rb", "")
Dir.mkdir("d3/sub")
File.write("d3/sub/c.txt", "")
p(Dir.glob("d3/*.rb"))              # => ["d3/b.rb"]
p(Dir.glob("d3/**/*.txt"))          # => ["d3/a.txt", "d3/sub/c.txt"]
p(Dir.glob(Any["d3/*.txt", "d3/*.rb"]))   # => ["d3/a.txt", "d3/b.rb"]
p(Dir.glob("*", base: "d3"))        # => ["a.txt", "b.rb", "sub"]
p(Dir.glob("nope/*"))               # => []
```

## exist?

`Dir.exist?(String)`

パスにディレクトリがあれば true。ファイルや無いパスは false で、失敗しません。

```ruby
Dir.mkdir("d4")
File.write("f4", "")
p(Dir.exist?("d4"))                 # => true
p(Dir.exist?("f4"))                 # => false
p(Dir.exist?("nope"))               # => false
```

## empty?

`Dir.empty?(String)`

ディレクトリが空（`.` と `..` 以外に何も無い）なら true。無いディレクトリは `IOError`。

```ruby
Dir.mkdir("d5")
p(Dir.empty?("d5"))                 # => true
File.write("d5/a", "")
p(Dir.empty?("d5"))                 # => false
```

## mkdir

`Dir.mkdir(String, [Integer])`

ディレクトリを 1 つ作り、0 を返します。第 2 引数は許可ビット（`0o700` など。省略時は `0o777` を umask で削ったもの）。親が無いときや、同じ名前が既にあるときは `IOError`（Ruby の `mkdir -p` に当たるものはありません）。

```ruby
p(Dir.mkdir("d6"))                  # => 0
p(Dir.mkdir("d6/sub", 0o700))       # => 0
p(Dir.exist?("d6/sub"))             # => true
```

```ruby error
Dir.mkdir("d6b")
Dir.mkdir("d6b")                    # !> IOError: Dir.mkdir: File exists
```

## rmdir, unlink

`Dir.rmdir(String)`

`Dir.unlink(String)`

空のディレクトリを消し、0 を返します（2 つは同じ。Ruby と同じ）。空でないディレクトリや無いパスは `IOError`。ファイルを消すのは `File.delete`。

```ruby
Dir.mkdir("d7")
p(Dir.rmdir("d7"))                  # => 0
p(Dir.exist?("d7"))                 # => false
Dir.mkdir("d7")
p(Dir.unlink("d7"))                 # => 0
```

```ruby error
Dir.mkdir("d7b")
File.write("d7b/a", "")
Dir.rmdir("d7b")                    # !> IOError: Dir.rmdir: Directory not empty
```

## pwd

`Dir.pwd()`

現在のディレクトリの絶対パス。Sake に `Dir.chdir` は無いので、プログラムの間変わりません。

```ruby
p(File.absolute_path?(Dir.pwd))     # => true
p(Dir.pwd == File.expand_path("."))   # => true
```

## home

`Dir.home([String])`

ホームディレクトリの絶対パス。引数にユーザー名を与えるとそのユーザーのホームです。知らないユーザーは `ArgumentError`。

```ruby
p(Dir.home == ENV.fetch("HOME"))    # => true
p(File.expand_path("~") == Dir.home)   # => true
```

```ruby error
Dir.home("no_such_user_xyz")        # !> ArgumentError: Dir.home: user no_such_user_xyz doesn't exist
```

## tmpdir

`Dir.tmpdir()`

一時ファイル用のディレクトリ（`$TMPDIR` か `/tmp`）の絶対パス。

```ruby
p(Dir.exist?(Dir.tmpdir))           # => true
p(File.absolute_path?(Dir.tmpdir))  # => true
```

## mktmpdir

`Dir.mktmpdir([String], [String]) [{ }]`

新しい一時ディレクトリを作ります。第 1 引数は名前の接頭辞（省略時 `"d"`）、第 2 引数は作る場所（省略時 `Dir.tmpdir`）。ブロック無しならそのパス（String）を返し、消すのは呼ぶ側の仕事です（`Dir.rmdir` は空のときだけ）。ブロックを付けるとパスをブロックに渡し、ブロックの後にディレクトリを**中身ごと**消して、ブロックの値を返します（Ruby の `tmpdir` と同じ）。場所が無ければ `IOError`。

```ruby
t = Dir.mktmpdir("pfx", ".")
p(String.start_with?(File.basename(t), "pfx"))   # => true
p(Dir.exist?(t))                    # => true
Dir.rmdir(t)
kept = ""
v = Dir.mktmpdir { |dir| File.write(File.join(dir, "f"), "1"); kept = dir; 42 }
p(v)                                # => 42
p(Dir.exist?(kept))                 # => false
```

# ENV

ENV はプロセスの環境変数を読み書きする操作の集まりです。Ruby の `ENV["X"]` は `ENV.get("X")`、`ENV["X"] = v` は `ENV.set("X", v)` と書きます（Sake では `ENV` は値ではなく、添字を付けられません。[組み込み](../09-builtins.md)）。名前も値も String です。

変更はこのプロセスと、以後に `Open3` や `Kernel.system` で起こす子プロセスに見えます。`ENV.to_h` は写しで、変えても環境は変わりません。Hash 全体を環境として戻すのが `ENV.replace(h)` です。

ENV に演算子はありません。例は `SAKE_DOC_` で始まる名前を使い、終わりに消します。

## get

`ENV.get(String)`

変数の値（String）、設定されていなければ nil です（Ruby の `ENV["X"]`）。結果は `String | nil` なので、`--strict`（レベル 2）は確かめずに使うことを `nil` の問題として報告します。必ずある変数には `fetch` を使います。

```ruby
ENV.set("SAKE_DOC_A", "1")
p(ENV.get("SAKE_DOC_A"))            # => "1"
p(ENV.get("SAKE_DOC_NOPE"))         # => nil
v = ENV.get("SAKE_DOC_A")
if v
  p(String.to_i(v) + 1)             # => 2
end
ENV.delete("SAKE_DOC_A")
```

```ruby error
home = ENV.get("HOME")
p(String.size(home))                # !> argument 1 may be nil
```

## fetch

`ENV.fetch(String, [String])`

変数の値（String）。設定されていなければ、第 2 引数があればそれを返し、無ければ `KeyError` です（Ruby の `ENV.fetch`。ブロック形はありません）。結果は nil になりません。

```ruby
ENV.set("SAKE_DOC_B", "x")
p(ENV.fetch("SAKE_DOC_B"))          # => "x"
p(ENV.fetch("SAKE_DOC_NOPE", "dflt"))   # => "dflt"
ENV.delete("SAKE_DOC_B")
```

```ruby error
ENV.fetch("SAKE_DOC_NOPE")          # !> KeyError: ENV.fetch: key not found: "SAKE_DOC_NOPE"
```

## set

`ENV.set(String, String)`

変数を設定し（あれば置き換え）、値を返します（Ruby の `ENV["X"] = v`）。値は String だけで、他の型は静的に `type` の問題です（消すのは `delete`）。空の名前や `=` を含む名前は OS が拒み、OS のメッセージを持つ `ArgumentError`（`Invalid argument - setenv()`）になります。rescue できます。

```ruby
p(ENV.set("SAKE_DOC_C", "1"))       # => "1"
p(ENV.set("SAKE_DOC_C", "2"))       # => "2"
out, status = Open3.capture2("sh", "-c", "echo $SAKE_DOC_C")
p(out)                              # => "2\n"
ENV.delete("SAKE_DOC_C")
```

```ruby error
ENV.set("SAKE_DOC_C", 1)            # !> ENV.set: argument 2 must be String, but is Integer
```

```ruby error
ENV.set("", "v")                    # !> ArgumentError: ENV.set: Invalid argument - setenv()
```

## key?

`ENV.key?(String)`

変数が設定されていれば true（値が空文字列でも true）。

```ruby
ENV.set("SAKE_DOC_D", "")
p(ENV.key?("SAKE_DOC_D"))           # => true
p(ENV.key?("SAKE_DOC_NOPE"))        # => false
ENV.delete("SAKE_DOC_D")
```

## delete

`ENV.delete(String)`

変数を消し、消した値（String）を返します。設定されていなければ nil（`String | nil`、レベル 2）。

```ruby
ENV.set("SAKE_DOC_E", "1")
p(ENV.delete("SAKE_DOC_E"))         # => "1"
p(ENV.delete("SAKE_DOC_E"))         # => nil
p(ENV.key?("SAKE_DOC_E"))           # => false
```

## keys

`ENV.keys()`

設定されている変数の名前すべての Array（String）。順序は決まっていません。

```ruby
ENV.set("SAKE_DOC_F", "1")
p(Array.include?(ENV.keys, "SAKE_DOC_F"))   # => true
p(Array.include?(ENV.keys, "SAKE_DOC_NOPE"))   # => false
ENV.delete("SAKE_DOC_F")
```

## to_h

`ENV.to_h()`

環境全体の写しを Hash（String → String）で返します。写しなので、Hash を変えても環境は変わらず、以後の `ENV.set` も Hash に映りません。

```ruby
ENV.set("SAKE_DOC_G", "1")
h = ENV.to_h
p(h["SAKE_DOC_G"])                  # => "1"
h["SAKE_DOC_H"] = "2"
p(ENV.key?("SAKE_DOC_H"))           # => false
ENV.delete("SAKE_DOC_G")
p(Hash.key?(h, "SAKE_DOC_G"))       # => true
```

## replace

`ENV.replace(Hash)`

環境全体を Hash の組で置き換え、nil を返します（Ruby の `ENV.replace`）: Hash に無い変数はすべて消え、各組が設定されます。キーも値も String でなければなりません。検査器はキーや値の型が他のものである Hash を拒みます（`the value must be String, but is Integer`、`argument key must be String, but is :a`。関数の引数を通しても同じ）。型が見られない場所（`--strict=0` で走らせたプログラム）では、String でないキーや値は実行時に `TypeError`（`keys and values must be String, got String => Integer`）で、何かを変える前に投げられるので環境はそのままです。典型的な使い方は `ENV.to_h` で取った写しを戻すことです。

```ruby
saved = ENV.to_h
p(ENV.replace(Hash.of("SAKE_DOC_R" => "1")))   # => nil
p(ENV.keys)                         # => ["SAKE_DOC_R"]
p(ENV.get("SAKE_DOC_R"))            # => "1"
ENV.replace(saved)
p(ENV.key?("SAKE_DOC_R"))           # => false
p(ENV.to_h == saved)                # => true
```

```ruby error
ENV.replace(Hash.of("SAKE_DOC_R" => 1))   # !> ENV.replace: the value must be String, but is Integer [type]
```

# Process

Process はこのプロセスの情報と時計を読む操作の集まりです。Ruby の `Process.pid` と `Process.clock_gettime` だけがあり、`fork`、`spawn`、`wait`、`kill` などはありません（子プロセスは [Open3](Open3.md) と `Kernel.system` で起こします）。Ruby の定数 `Process::CLOCK_MONOTONIC` は Sake では操作 `Process.CLOCK_MONOTONIC` です（`Math.PI` と同じく、Sake に値の定数は無いので。[組み込み](../09-builtins.md)）。

Process に演算子はありません。例は環境に依らない値だけを表示します。

## pid

`Process.pid()`

このプロセスの ID（正の Integer）。子プロセスから見た親の ID は `Open3` で `$PPID` を読めば得られます。

```ruby
p(Process.pid > 0)                  # => true
out, status = Open3.capture2("sh", "-c", "echo $PPID")
p(String.to_i(out) == Process.pid)  # => true
```

## clock_gettime

`Process.clock_gettime(Integer, [Symbol])`

時計 `clock`（下の 3 つの操作のどれかの値）の現在値を返します（Ruby の `Process.clock_gettime`）。経過時間を測るには `Process.CLOCK_MONOTONIC` を使います: 壁時計の調整で戻ることがありません。第 2 引数は Ruby と同じ単位の Symbol で、結果の型を決めます: 省略時と `:float_second`（既定）、`:float_millisecond`、`:float_microsecond` では Float、`:second`、`:millisecond`、`:microsecond`、`:nanosecond` では Integer です。検査器は Symbol リテラルで書かれた単位を読みます。変数に入れた単位では結果は `Integer | Float` になり、Integer や Float の操作に渡す前に `case`/`in` で分ける必要があります。知らない単位（`unexpected unit: bogus`）と知らない時計の番号（`Invalid argument - clock_gettime(999)`）は `ArgumentError` です。

```ruby
t0 = Process.clock_gettime(Process.CLOCK_MONOTONIC)
t1 = Process.clock_gettime(Process.CLOCK_MONOTONIC)
p(t1 >= t0)                         # => true
p(Process.clock_gettime(Process.CLOCK_REALTIME) > 1.0e9)   # => true
ms = Process.clock_gettime(Process.CLOCK_MONOTONIC, :millisecond)
p(ms > 0)                           # => true
p(Integer.to_s(ms) == "#{ms}")      # => true
f = Process.clock_gettime(Process.CLOCK_MONOTONIC, :float_millisecond)
p(Float.floor(f) >= 0)              # => true
```

```ruby error
Process.clock_gettime(Process.CLOCK_MONOTONIC, :bogus)   # !> ArgumentError: Process.clock_gettime: unexpected unit: bogus
```

```ruby error
Process.clock_gettime(999)          # !> ArgumentError: Process.clock_gettime: Invalid argument - clock_gettime(999)
```

```ruby error
unit = :millisecond
p(Integer.to_s(Process.clock_gettime(Process.CLOCK_MONOTONIC, unit)))   # !> Integer.to_s: argument 1 must be Integer, but can be Float
```

## CLOCK_REALTIME, CLOCK_MONOTONIC, CLOCK_PROCESS_CPUTIME_ID

`Process.CLOCK_REALTIME()`

`Process.CLOCK_MONOTONIC()`

`Process.CLOCK_PROCESS_CPUTIME_ID()`

`clock_gettime` に渡す時計の番号（Integer）。`CLOCK_REALTIME` は壁時計（1970-01-01 UTC からの秒。`Time.now` と同じ値）、`CLOCK_MONOTONIC` は起点が不定で決して戻らない時計（経過時間用）、`CLOCK_PROCESS_CPUTIME_ID` はこのプロセスが使った CPU 時間です。番号そのものは OS で決まり、Linux では 0、1、2 です。他の Ruby の時計（`CLOCK_THREAD_CPUTIME_ID` など）はありません。

```ruby
p(Process.CLOCK_REALTIME != Process.CLOCK_MONOTONIC)   # => true
wall = Process.clock_gettime(Process.CLOCK_REALTIME)
p(Float.abs(wall - Time.to_f(Time.now)) < 1.0)         # => true
p(Process.clock_gettime(Process.CLOCK_PROCESS_CPUTIME_ID) >= 0.0)   # => true
```

# Open3

Open3 は子プロセスを走らせて出力と終了状態を集める操作の集まりです（Ruby の `open3` ライブラリの `capture2`、`capture2e`、`capture3`。Sake のプログラムは他に子プロセスを起こす手段が無いので組み込みです。出力を集めず true/false だけ欲しければ `Kernel.system`。[組み込み](../09-builtins.md)）。

Ruby の結果は Array `[out, status]` で `status` は `Process::Status` ですが、Sake では **Tuple** で、終了状態は **Integer**（終了コード。シグナルで死んだときは -1）です。`out, status = Open3.capture2(...)` と多重代入で受けます。コマンドが見つからない・起動できないときは `IOError`。コマンドは Ruby と同じく、1 引数なら shell で解釈、2 引数以上なら第 1 引数がプログラムで残りが引数（shell を通しません）。標準入力は与えられません（Ruby の `stdin_data:` はありません）。

Open3 に演算子はありません。

## capture2

`Open3.capture2(String, *String)`

コマンドを走らせ、`[stdout, status]`（String, Integer）の Tuple を返します。子の stderr はこのプロセスの stderr にそのまま流れます。

```ruby
out, status = Open3.capture2("echo", "hi")
p(out)                              # => "hi\n"
p(status)                           # => 0
out2, status2 = Open3.capture2("sh", "-c", "echo $0; exit 3")
p(out2)                             # => "sh\n"
p(status2)                          # => 3
```

```ruby error
Open3.capture2("no_such_command_xyz")   # !> IOError: Open3.capture2: No such file or directory - no_such_command_xyz
```

## capture2e

`Open3.capture2e(String, *String)`

コマンドを走らせ、stdout と stderr を 1 つに混ぜた `[output, status]`（String, Integer）の Tuple を返します（Ruby の `capture2e`）。

```ruby
out, status = Open3.capture2e("sh", "-c", "echo err >&2; echo out; exit 2")
p(out)                              # => "err\nout\n"
p(status)                           # => 2
```

## capture3

`Open3.capture3(String, *String)`

コマンドを走らせ、`[stdout, stderr, status]`（String, String, Integer）の Tuple を返します。

```ruby
out, err, status = Open3.capture3("sh", "-c", "echo err >&2; echo out; exit 2")
p(out)                              # => "out\n"
p(err)                              # => "err\n"
p(status)                           # => 2
p(Open3.capture3("true"))           # => ["", "", 0]
killed = Open3.capture3("sh", "-c", "kill -9 $$")
p(killed[2])                        # => -1
```

# Zlib

Zlib は String を zlib 形式・gzip 形式で圧縮・展開する操作の集まりです（Ruby の `Zlib.deflate`、`inflate`、`gzip`、`gunzip`。速度のために組み込みです。[組み込み](../09-builtins.md)）。圧縮レベルやストリームの形（`Zlib::Deflate` クラスなど）はありません。

圧縮した結果と展開した結果はどちらもバイナリの String（エンコーディング `ASCII-8BIT`）です。UTF-8 の文字列を展開した結果と元の文字列は、バイトは同じでもエンコーディングが違うので `==` になりません: 文字列として使うなら `String.force_encoding(s, "UTF-8")` を通します。壊れた入力や形式の違う入力（`inflate` に gzip を渡す、など）は `ArgumentError` で、メッセージは zlib のもの（`incorrect header check` など。Ruby の `Zlib::DataError` 等に当たる例外型はありません）。

Zlib に演算子はありません。

## deflate, inflate

`Zlib.deflate(String)`

`Zlib.inflate(String)`

`deflate` は zlib 形式（RFC 1950）に圧縮した String、`inflate` はそれを元に戻した String を返します。空の文字列も圧縮・展開できますが、`inflate("")` は `ArgumentError`（`buffer error`）です。

```ruby
s = String.*("hello ", 100)
z = Zlib.deflate(s)
p(String.bytesize(z) < String.bytesize(s))   # => true
p(Zlib.inflate(z) == s)                      # => true
p(String.encoding(Zlib.inflate(z)))          # => "ASCII-8BIT"
j = Zlib.inflate(Zlib.deflate("日本"))
p(j == "日本")                               # => false
p(String.force_encoding(j, "UTF-8") == "日本")   # => true
```

```ruby error
Zlib.inflate("not compressed")      # !> ArgumentError: Zlib.inflate: incorrect header check
```

## gzip, gunzip

`Zlib.gzip(String)`

`Zlib.gunzip(String)`

`gzip` は gzip 形式（RFC 1952。`gzip` コマンドや `.gz` ファイルと同じで、先頭 2 バイトは `0x1f 0x8b`）に圧縮した String、`gunzip` はそれを元に戻した String を返します。`deflate` の結果を `gunzip` に、`gzip` の結果を `inflate` に渡すことはできません（`ArgumentError`）。

```ruby
g = Zlib.gzip("hello")
p(String.getbyte(g, 0))             # => 31
p(String.getbyte(g, 1))             # => 139
p(Zlib.gunzip(g))                   # => "hello"
File.write("a.gz", g)
out, status = Open3.capture2("sh", "-c", "gunzip -c a.gz")
p(out)                              # => "hello"
```

```ruby error
Zlib.gunzip(Zlib.deflate("x"))      # !> ArgumentError: Zlib.gunzip:
```

# Thread

Thread はブロックを並行に走らせるスレッドの型です。`Thread.new { ... }` が作り、`Thread.value(t)` か `Thread.join(t)` で終わりを待ちます。Ruby の `Thread` と同じ仕組み（Ruby のスレッドそのもの）ですが、操作はここに挙げたものだけで、`Thread#[]`、`status`、`priority`、`Thread.pass` などはありません。Thread のリテラルはなく、値は `Thread.new` と `Thread.current` から来ます（[値と型](../03-values.md)、[組み込み](../09-builtins.md)）。

- **変数。** ブロックは周りの変数を共有しますが、スレッドでは `Thread.new` を囲むブロックの変数（引数とローカル）とスレッドブロック自身の変数は開始時に複製され、関数（トップレベル）の変数は共有のままです。共有カウンタは `Mutex.synchronize` の中で更新します（[Mutex](Mutex.md)）。
- **抜け方。** スレッドブロックからの `break` と `return` は静的エラーです（ブロックは `Thread.new` が戻った後で走る）。`next v` が `v` で終えます。
- **エラー。** スレッドの中の例外はそこでは報告されず、`Thread.value` か `Thread.join` を呼んだ側で上がります。エラーで終わったのに `Thread.value` / `Thread.join` で読まれなかったスレッドは、プログラムの終了時に stderr に報告されます（終了ステータスは変わりません）: `PATH: a thread ended with an error that no Thread.value / Thread.join read:` の後に、そのエラーの報告が字下げされて続きます。メインプログラムが終わるとすべてのスレッドが止まり、そのときまだ走っていたスレッドは報告されません。
- **検査。** 検査器はブロックを `Thread.new` の場所で 1 度走らせ、その値を `Thread.value` の型にします。実行の交互は解析せず、各操作が実行時に引数を検査します。

Thread に使える演算子は `==`、`!=` だけです（同じスレッドなら等しい）。

## new

`Thread.new() { }`

ブロックを新しいスレッドで走らせ始め、すぐに Thread を返します。ブロックの値がスレッドの値（`Thread.value`）です。ブロックは必須で、引数は受け取りません。

```ruby
t = Thread.new { 1 + 2 }
p(t)                                # => #<Thread>
p(Thread.value(t))                  # => 3
ws = Array.map(Any[1, 2, 3]) { |i| Thread.new { i * 10 } }
p(Array.map(ws) { |w| Thread.value(w) })   # => [10, 20, 30]
```

```ruby error
t = Thread.new { return 1 }         # !> `return` outside a function
```

## value

`Thread.value(x)`

スレッドが終わるのを待ち、ブロックの値を返します（Ruby の `t.value`）。何度呼んでも同じ値です。スレッドが例外で終わっていれば、その例外がここで上がります（何度でも）。`Thread.kill` で止められたスレッドの値は nil です。結果の型はブロックの型で、nil を返しうるブロックなら `nil` の検査を受けます。自分自身（`Thread.current`）を待つことはできず、`ThreadError`（`Target thread must not be current thread`）です。

```ruby
t = Thread.new { "done" }
p(Thread.value(t))                  # => "done"
p(Thread.value(t))                  # => "done"
e = Thread.new { raise ArgumentError, "boom" }
begin
  Thread.value(e)
rescue ArgumentError => err
  p(Exception.message(err))         # => "boom"
end
```

```ruby error
t = Thread.new { raise ArgumentError, "boom" }
Thread.value(t)                     # !> ArgumentError: boom
```

```ruby error
Thread.value(Thread.current)        # !> ThreadError: Thread.value: Target thread must not be current thread
```

例外で終わったスレッドをどの `value` / `join` も読まずにプログラムが終わると、そのエラーは stderr に報告されます（終了ステータスは 0 のまま）。検査器は stderr が空であることを求めるので、端末での見え方をそのまま示します:

```
t = Thread.new { raise ArgumentError, "boom" }
Thread.join(Thread.new { 1 })
p(1)                                # 1 と出た後、stderr に:
                                    # ex.sake: a thread ended with an error that no Thread.value / Thread.join read:
                                    #   ex.sake:1: in <main>: ArgumentError: boom
```

## join

`Thread.join(x, [Integer|Float|Rational])`

スレッドが終わるのを待ち、スレッドを返します。第 2 引数に秒数を与えると、その時間を過ぎても終わらないときは待つのをやめて nil を返します（スレッドは走り続けます）。結果は 2 引数のときだけ `Thread | nil` で、レベル 2 で検査されます: `if Thread.join(t, 5)` で「時間内に終わった」が分かります（`sakelib` の `Timeout.timeout` はこう作られています）。スレッドの例外は `value` と同じくここで上がります。自分自身を待つことはできません（`ThreadError`）。

```ruby
q = Queue.new
t = Thread.new { Queue.pop(q) }
p(Thread.join(t, 0.01))             # => nil
p(Thread.alive?(t))                 # => true
Queue.push(q, :go)
p(Thread.join(t) == t)              # => true
p(Thread.join(t, 1) == t)           # => true
```

## alive?

`Thread.alive?(x)`

スレッドがまだ走っている（終わっていない）なら true。

```ruby
q = Queue.new
t = Thread.new { Queue.pop(q) }
p(Thread.alive?(t))                 # => true
Queue.push(q, 1)
Thread.join(t)
p(Thread.alive?(t))                 # => false
p(Thread.alive?(Thread.current))    # => true
```

## current

`Thread.current()`

今走っているスレッド（メインプログラムのスレッド、または `Thread.new` で作ったもの）。同じスレッドを表す値はすべて `==` です。

```ruby
me = Thread.current
p(Thread.current == me)             # => true
t = Thread.new { Thread.current }
p(Thread.value(t) == t)             # => true
p(Thread.value(t) == me)            # => false
```

## kill

`Thread.kill(x)`

スレッドを今いる場所で止め、スレッドを返します（Ruby の `t.kill`）。`ensure` 節は走ります。止めたスレッドの `value` は nil、`alive?` は false。既に終わっているスレッドには何もしません。

```ruby
q = Queue.new
t = Thread.new { Queue.pop(q) }
p(Thread.kill(t) == t)              # => true
Thread.join(t)
p(Thread.alive?(t))                 # => false
p(Thread.value(t))                  # => nil
```

## raise

`Thread.raise(x, String)`

スレッドの今いる場所で `RuntimeError`（メッセージ付き）を起こし、スレッドを返します。スレッドの中で rescue されなければスレッドはそれで終わり、`value` や `join` を呼んだ側でその `RuntimeError` が上がります（`sakelib` の `Timeout.timeout` はこれでブロックを中断します）。既に終わっているスレッドには何もしません。`Thread.raise` を呼ぶプログラムでは、検査器は `Thread.value` と `Thread.join` が `RuntimeError` を投げうるものとして扱うので、それらを囲む `rescue RuntimeError => e` が通ります（`Thread.raise` の無いプログラムでは「本体は RuntimeError を投げない」という `rescue` の問題になります）。

```ruby
q = Queue.new
t = Thread.new { Queue.pop(q) }
p(Thread.raise(t, "stop") == t)     # => true
begin
  Thread.value(t)
rescue RuntimeError => e
  p(e)                              # => #<RuntimeError: stop>
end
begin
  Thread.join(t)
rescue RuntimeError => e
  p(Exception.message(e))           # => "stop"
end
done = Thread.new { 1 }
Thread.join(done)
Thread.raise(done, "late")
p(Thread.value(done))               # => 1
```

## ==, !=

`Thread.==(x, Any)`

`Thread.!=(x, Any)`

2 つの値が同じスレッドなら等しい（`!=` はその否定）。Thread 以外の値とは等しくありません。

```ruby
t = Thread.new { 1 }
p(t == t)                           # => true
p(t != Thread.new { 2 })            # => true
p(t == 1)                           # => false
```

# Mutex

Mutex はスレッドの間で排他をとる錠の型です（Ruby の `Thread::Mutex` そのもの）。`Mutex.new` が作り、`Mutex.synchronize(m) { ... }` がブロックの間だけ錠を持ちます。スレッドが共有する変数（関数やトップレベルの変数、Array や Hash の中身）を複数のスレッドから更新するときに使います（[Thread](Thread.md)、[組み込み](../09-builtins.md)）。リテラルはありません。

錠は再入できません: 持っているスレッドがもう一度 `lock` すると `ThreadError`（`deadlock; recursive locking`）です。持っていないスレッドが `unlock` するのも `ThreadError`。`ThreadError` は rescue できる組み込みの例外です（[例外](../08-exceptions.md)）。

Mutex に使える演算子は `==`、`!=` だけです（同じ Mutex なら等しい）。

## new

`Mutex.new()`

新しい、誰も持っていない Mutex を返します。

```ruby
m = Mutex.new
p(m)                                # => #<Mutex>
p(Mutex.locked?(m))                 # => false
```

## synchronize

`Mutex.synchronize(x) { }`

錠を取り、ブロックを走らせ、ブロックが終わると（例外で抜けても）錠を離し、ブロックの値を返します。他のスレッドが持っている間は待ちます。普通はこの形だけで足ります。自分が持っている Mutex の `synchronize` を入れ子にすると、`lock` と同じく `ThreadError`（`deadlock; recursive locking`）です。rescue でき、外側の `synchronize` は抜けるときに錠を離します。

```ruby
m = Mutex.new
count = 0
ths = Array.map(Any[1, 2, 3, 4]) { |i|
  Thread.new { Array.each(Array.new(100, 0)) { |_| Mutex.synchronize(m) { count += 1 } } }
}
Array.each(ths) { |t| Thread.join(t) }
p(count)                            # => 400
r = Mutex.synchronize(m) { p(Mutex.locked?(m)); "val" }   # => true
p(r)                                # => "val"
p(Mutex.locked?(m))                 # => false
begin
  Mutex.synchronize(m) { Mutex.synchronize(m) { 1 } }
rescue ThreadError => e
  p(Exception.message(e))           # => "deadlock; recursive locking"
end
p(Mutex.locked?(m))                 # => false
```

```ruby error
m = Mutex.new
Mutex.synchronize(m) { Mutex.synchronize(m) { 1 } }   # !> ThreadError: Mutex.synchronize: deadlock; recursive locking
```

## lock

`Mutex.lock(x)`

錠を取り、Mutex を返します。他のスレッドが持っていれば離されるまで待ちます。自分が既に持っていれば `ThreadError`。`unlock` と組にして使いますが、例外で抜けるときに離し忘れないよう、`synchronize` が普通です。

```ruby
m = Mutex.new
p(Mutex.lock(m) == m)               # => true
p(Mutex.locked?(m))                 # => true
Mutex.unlock(m)
```

```ruby error
m = Mutex.new
Mutex.lock(m)
Mutex.lock(m)                       # !> ThreadError: Mutex.lock: deadlock; recursive locking
```

## unlock

`Mutex.unlock(x)`

錠を離し、Mutex を返します。持っていない（誰も持っていない、または他のスレッドが持っている）Mutex は `ThreadError`。

```ruby
m = Mutex.new
Mutex.lock(m)
p(Mutex.unlock(m) == m)             # => true
p(Mutex.locked?(m))                 # => false
```

```ruby error
m = Mutex.new
Mutex.unlock(m)                     # !> ThreadError: Mutex.unlock: Attempt to unlock a mutex which is not locked
```

## try_lock

`Mutex.try_lock(x)`

錠が空いていれば取って true、誰かが持っていれば待たずに false を返します（自分が持っているときも false で、エラーにはなりません）。

```ruby
m = Mutex.new
p(Mutex.try_lock(m))                # => true
p(Mutex.try_lock(m))                # => false
other = Thread.new { Mutex.try_lock(m) }
p(Thread.value(other))              # => false
Mutex.unlock(m)
p(Mutex.try_lock(m))                # => true
```

## locked?

`Mutex.locked?(x)`

どのスレッドかに関わらず、誰かが錠を持っていれば true。

```ruby
m = Mutex.new
p(Mutex.locked?(m))                 # => false
Mutex.lock(m)
p(Mutex.locked?(m))                 # => true
p(Thread.value(Thread.new { Mutex.locked?(m) }))   # => true
```

## owned?

`Mutex.owned?(x)`

今のスレッドが錠を持っていれば true。他のスレッドが持っているときは false。

```ruby
m = Mutex.new
p(Mutex.owned?(m))                  # => false
Mutex.lock(m)
p(Mutex.owned?(m))                  # => true
p(Thread.value(Thread.new { Mutex.owned?(m) }))    # => false
```

## ==, !=

`Mutex.==(x, Any)`

`Mutex.!=(x, Any)`

同じ Mutex なら等しい（`!=` はその否定）。`Mutex.new` の結果はそれぞれ別の値です。

```ruby
m = Mutex.new
p(m == m)                           # => true
p(m == Mutex.new)                   # => false
p(m != Mutex.new)                   # => true
```

# Queue

Queue はスレッドの間で値を渡す、スレッド安全な先入れ先出しの待ち行列です（Ruby の `Thread::Queue` そのもの）。`Queue.push(q, x)` が末尾に加え、`Queue.pop(q)` が先頭を取り出し、空なら誰かが push するまで待ちます。`Queue.close(q)` が「もう来ない」を伝え、閉じて空になった Queue の `pop` は nil です。これで生産者・消費者のパターンが書けます（[Thread](Thread.md)、[組み込み](../09-builtins.md)）。リテラルはなく、長さの上限（Ruby の `SizedQueue`）はありません。

**要素の型。** 検査器にとって Queue の要素型は、その Queue に push されたものすべての和です。`Queue.pop` の型はそれに nil を加えたもので、`--strict`（レベル 2）はそのまま使うことを `nil` の問題として報告します: `while (x = Queue.pop(q))` で受けるのが普通の形です。

Queue に使える演算子は `==`、`!=` だけです（同じ Queue なら等しい）。

## new

`Queue.new()`

新しい空の Queue を返します。

```ruby
q = Queue.new
p(q)                                # => #<Queue>
p(Queue.empty?(q))                  # => true
```

## push

`Queue.push(x, Any)`

値を末尾に加え、Queue を返します。どんな値でも加えられ、nil も加えられますが、nil は `pop` 側で「閉じて空」と区別できません。閉じた Queue への push は `IOError`（Ruby では `ClosedQueueError`）。

```ruby
q = Queue.new
p(Queue.push(q, 1) == q)            # => true
Queue.push(q, "two")
p(Queue.size(q))                    # => 2
```

```ruby error
q = Queue.new
Queue.close(q)
Queue.push(q, 1)                    # !> IOError: Queue.push: push to a closed Queue
```

## pop

`Queue.pop(x, [Integer|Float|Rational])`

先頭の値を取り出して返します。空なら、誰かが push するか Queue が閉じられるまで待ちます。閉じていて空なら待たずに nil。第 2 引数に秒数を与えると、その時間待っても何も来なければ nil を返します（0 なら待ちません）。結果は常に「要素の型 | nil」で、レベル 2 で検査されます。

```ruby
q = Queue.new
Queue.push(q, 1)
Queue.push(q, 2)
p(Queue.pop(q))                     # => 1
p(Queue.pop(q, 5))                  # => 2
p(Queue.pop(q, 0.01))               # => nil
workers = Array.map(Any[1, 2]) { |i|
  Thread.new { total = 0; while (x = Queue.pop(q)); total += x; end; total }
}
Array.each(Any[1, 2, 3, 4, 5, 6]) { |i| Queue.push(q, i) }
Queue.close(q)
p(Array.sum(Array.map(workers) { |w| Thread.value(w) }))   # => 21
```

```ruby error
q = Queue.new
Queue.push(q, 1)
p(Queue.pop(q) + 1)                 # !> the operands may be nil
```

## close

`Queue.close(x)`

Queue を閉じて返します。以後の `push` は `IOError`、`pop` は残りを順に返した後 nil を返し、待っている `pop` はすべて nil で起きます。もう一度閉じても何も起きません。

```ruby
q = Queue.new
Queue.push(q, 1)
p(Queue.close(q) == q)              # => true
p(Queue.pop(q))                     # => 1
p(Queue.pop(q))                     # => nil
```

## closed?

`Queue.closed?(x)`

閉じられていれば true。

```ruby
q = Queue.new
p(Queue.closed?(q))                 # => false
Queue.close(q)
p(Queue.closed?(q))                 # => true
```

## size

`Queue.size(x)`

今入っている値の個数（Integer）。

```ruby
q = Queue.new
p(Queue.size(q))                    # => 0
Queue.push(q, :a)
Queue.push(q, :b)
p(Queue.size(q))                    # => 2
Queue.pop(q)
p(Queue.size(q))                    # => 1
```

## empty?

`Queue.empty?(x)`

何も入っていなければ true。

```ruby
q = Queue.new
p(Queue.empty?(q))                  # => true
Queue.push(q, 1)
p(Queue.empty?(q))                  # => false
```

## ==, !=

`Queue.==(x, Any)`

`Queue.!=(x, Any)`

同じ Queue なら等しい（`!=` はその否定）。`Queue.new` の結果はそれぞれ別の値です。

```ruby
q = Queue.new
p(q == q)                           # => true
p(q == Queue.new)                   # => false
p(q != Queue.new)                   # => true
```

# Socket

Socket は TCP 接続の型です。値は `Socket.connect(host, port)`（平文）、`Socket.connect_ssl(host, port)`（TLS）、そしてサーバ側の `TCPServer.accept` から来ます（[TCPServer](TCPServer.md)）。どれも同じ型 `Socket` で、同じ操作で読み書きします（Ruby の `TCPSocket` と `OpenSSL::SSL::SSLSocket`。[組み込み](../09-builtins.md)）。読む操作は `IO` と同じ形（`gets`、`read`）ですが、Socket は `IO` ではなく、`IO.puts` などには渡せません。

接続できない・切れた・名前が解けないといったネットワークの失敗は `IOError` です（Ruby の `Errno::ECONNREFUSED`、`SocketError`、`OpenSSL::SSL::SSLError` などをまとめたもの。[例外](../08-exceptions.md)）。読み書きの待ち時間は `set_timeout` で決め、過ぎると `IOError`。`gets` と `read` が返す String はバイナリ（エンコーディング `ASCII-8BIT`）で、文字列として使うには `String.force_encoding(s, "UTF-8")` を通します。UDP や Unix ドメインソケットはありません。

Socket に使える演算子は `==`、`!=` だけです（同じ接続なら等しい）。例は `127.0.0.1` のポート 0 に `TCPServer` を立て、同じプログラムの Thread から接続します。

## connect

`Socket.connect(String, Integer, [Integer|Float|Rational])`

`host`（名前か IP アドレス）の `port` に TCP で接続し、Socket を返します。第 3 引数は接続を待つ秒数で、過ぎると `IOError`（省略時は OS の既定まで待ちます）。接続を拒まれたときも、名前が解けないとき（Ruby の `Socket::ResolutionError`）も `IOError` です。名前が解けないときのメッセージはリゾルバのもの（`getaddrinfo(3): Name or service not known` など）です。

```ruby
srv = TCPServer.new("127.0.0.1", 0)
port = TCPServer.port(srv)
client = Thread.new {
  s = Socket.connect("127.0.0.1", port, 5)
  Socket.write(s, "ping\n")
  reply = Socket.gets(s)
  Socket.close(s)
  reply
}
conn = TCPServer.accept(srv)
p(Socket.gets(conn))                # => "ping\n"
Socket.write(conn, "pong\n")
Socket.close(conn)
p(Thread.value(client))             # => "pong\n"
TCPServer.close(srv)
```

```ruby error
Socket.connect("127.0.0.1", 1)      # !> IOError: Socket.connect: Connection refused
```

```ruby error
Socket.connect("no-such-host.invalid", 80)   # !> IOError: Socket.connect: getaddrinfo
```

## connect_ssl

`Socket.connect_ssl(String, Integer, [Integer|Float|Rational])`

`host` の `port` に TCP で接続し、その上で TLS のハンドシェイクをして Socket を返します。相手の証明書は OS の信頼ストアで検証し、`host` を SNI とホスト名の検査に使います（Ruby の `OpenSSL::SSL::SSLSocket` に `VERIFY_PEER`）。第 3 引数は TCP の接続を待つ秒数。接続の失敗もハンドシェイクの失敗（TLS を話さない相手、検証できない証明書）も `IOError`。`close` は TLS と TCP の両方を閉じます。外部に繋ぐ例は検査器の中では走らせられないので、ここでは形だけ示します:

```
s = Socket.connect_ssl("example.com", 443, 10)
Socket.write(s, "GET / HTTP/1.0\r\nHost: example.com\r\n\r\n")
p(Socket.gets(s))                   # "HTTP/1.0 200 OK\r\n" など
Socket.close(s)
```

TLS を話さないサーバに繋ぐとハンドシェイクが `IOError` になります:

```ruby error
srv = TCPServer.new("127.0.0.1", 0)
port = TCPServer.port(srv)
t = Thread.new { c = TCPServer.accept(srv); Socket.close(c) }
Socket.connect_ssl("127.0.0.1", port)   # !> IOError: Socket.connect_ssl:
```

## set_timeout

`Socket.set_timeout(x, Integer|Float|Rational|Nil)`

以後の `gets`、`read`、`write` が待つ秒数を決め、Socket を返します（Ruby の `IO#timeout=`）。過ぎると `IOError`（`Blocking operation timed out!`）。nil で無制限（既定）に戻ります。

```ruby
srv = TCPServer.new("127.0.0.1", 0)
s = Socket.connect("127.0.0.1", TCPServer.port(srv))
p(Socket.set_timeout(s, 0.05) == s)   # => true
begin
  Socket.gets(s)
rescue IOError => e
  p(Exception.message(e))           # => "Blocking operation timed out!"
end
Socket.set_timeout(s, nil)
Socket.close(s)
TCPServer.close(srv)
```

## gets

`Socket.gets(x)`

次の 1 行を改行を含めて返し、相手が書き込み側を閉じて（`close_write` か `close`）データが尽きたら nil です。結果は `String | nil` で、`--strict`（レベル 2）は確かめずに使うことを `nil` の問題として報告します。`set_timeout` の時間を過ぎると `IOError`。

```ruby
srv = TCPServer.new("127.0.0.1", 0)
port = TCPServer.port(srv)
t = Thread.new {
  s = Socket.connect("127.0.0.1", port)
  Socket.write(s, "a\nb\n")
  Socket.close(s)
}
c = TCPServer.accept(srv)
while (line = Socket.gets(c))
  p(line)                           # => "a\n"
                                    # => "b\n"
end
p(Socket.gets(c))                   # => nil
Thread.join(t)
TCPServer.close(srv)
```

## read

`Socket.read(x, Integer)`

ちょうど `n` バイト読んで返します。`n` バイト溜まるまで待ち、その前に相手が閉じれば残りだけを返し、もう何も無ければ nil です（`String | nil`、レベル 2。`n` が 0 なら常に `""`）。負の `n` は `ArgumentError`。Ruby の `read` と違い、引数無しの形（終端まで読む）はありません。

```ruby
srv = TCPServer.new("127.0.0.1", 0)
port = TCPServer.port(srv)
t = Thread.new {
  s = Socket.connect("127.0.0.1", port)
  Socket.write(s, "hello")
  Socket.close(s)
}
c = TCPServer.accept(srv)
p(Socket.read(c, 2))                # => "he"
p(Socket.read(c, 10))               # => "llo"
p(Socket.read(c, 10))               # => nil
p(Socket.read(c, 0))                # => ""
Thread.join(t)
TCPServer.close(srv)
```

```ruby error
srv = TCPServer.new("127.0.0.1", 0)
s = Socket.connect("127.0.0.1", TCPServer.port(srv))
Socket.read(s, -1)                  # !> ArgumentError: Socket.read: negative size -1
```

## write

`Socket.write(x, String)`

文字列を送り、送ったバイト数（Integer）を返します。改行は加えません。閉じた Socket や `close_write` の後は `IOError`。

```ruby
srv = TCPServer.new("127.0.0.1", 0)
port = TCPServer.port(srv)
t = Thread.new {
  s = Socket.connect("127.0.0.1", port)
  n = Socket.write(s, "日本\n")
  Socket.close(s)
  n
}
c = TCPServer.accept(srv)
got = Socket.gets(c)
if got
  p(String.encoding(got))           # => "ASCII-8BIT"
  p(String.force_encoding(got, "UTF-8"))   # => "日本\n"
end
p(Thread.value(t))                  # => 7
TCPServer.close(srv)
```

```ruby error
srv = TCPServer.new("127.0.0.1", 0)
s = Socket.connect("127.0.0.1", TCPServer.port(srv))
Socket.close(s)
Socket.write(s, "x")                # !> IOError: Socket.write: closed stream
```

## close_write

`Socket.close_write(x)`

書き込み側だけを閉じて nil を返します（TCP の半閉鎖）。相手の `gets` や `read` はデータが尽きた後 nil を受け取り、こちらは引き続き相手からの返事を読めます。「全部送ったら返事を待つ」プロトコルに使います。この後の `write` は `IOError`。

```ruby
srv = TCPServer.new("127.0.0.1", 0)
port = TCPServer.port(srv)
client = Thread.new {
  s = Socket.connect("127.0.0.1", port)
  Socket.write(s, "1 2 3")
  Socket.close_write(s)
  reply = Socket.gets(s)
  Socket.close(s)
  reply
}
c = TCPServer.accept(srv)
body = Socket.read(c, 100)
if body
  Socket.write(c, String.upcase(body) + "\n")
end
Socket.close(c)
p(Thread.value(client))             # => "1 2 3\n"
TCPServer.close(srv)
```

## close

`Socket.close(x)`

接続を閉じて nil を返します（TLS なら TCP も閉じます）。もう一度閉じても何も起きません。閉じた後の読み書きは `IOError`。

```ruby
srv = TCPServer.new("127.0.0.1", 0)
s = Socket.connect("127.0.0.1", TCPServer.port(srv))
p(Socket.close(s))                  # => nil
p(Socket.close(s))                  # => nil
TCPServer.close(srv)
```

## ==, !=

`Socket.==(x, Any)`

`Socket.!=(x, Any)`

2 つの値が同じ Socket なら等しい（`!=` はその否定）。1 つの接続の両端（クライアントの `connect` とサーバの `accept`）は別の Socket です。Socket 以外の値とは等しくなく、関数形でも false になります（エラーにはなりません）。

```ruby
srv = TCPServer.new("127.0.0.1", 0)
s = Socket.connect("127.0.0.1", TCPServer.port(srv))
c = TCPServer.accept(srv)
p(s == s)                           # => true
p(s == c)                           # => false
p(s != c)                           # => true
p(Socket.==(s, 1))                  # => false
Socket.close(s)
Socket.close(c)
TCPServer.close(srv)
```

# TCPServer

TCPServer は TCP の接続を受け付ける待ち受けソケットの型です（Ruby の `TCPServer`）。`TCPServer.new(host, port)` がポートを開き、`TCPServer.accept(s)` が次の接続を待って `Socket` を返します。受け付けた接続は [Socket](Socket.md) の操作で読み書きします（[組み込み](../09-builtins.md)）。リテラルはありません。

ポートを開けない（使用中、権限が無い）、閉じたサーバで accept する、などの失敗は `IOError` です（[例外](../08-exceptions.md)）。

TCPServer に使える演算子は `==`、`!=` だけです（同じサーバなら等しい）。例は `127.0.0.1` のポート 0（空いているポートを OS が選ぶ）で立て、同じプログラムの Thread から接続します。

## new

`TCPServer.new(String, Integer)`

`host` のアドレスの `port` で待ち受けを始め、TCPServer を返します。`host` は `"127.0.0.1"`（ローカルだけ）、`"0.0.0.0"`（すべてのインターフェース）、`"localhost"` などで、省略できません（Ruby の `TCPServer.new(port)` の形はありません）。`port` が 0 なら空いているポートを OS が選び、`TCPServer.port` で分かります。使用中のポートや権限の無いポート（1024 未満）は `IOError`。

```ruby
srv = TCPServer.new("127.0.0.1", 0)
p(srv)                              # => #<TCPServer>
p(TCPServer.port(srv) > 0)          # => true
TCPServer.close(srv)
```

```ruby error
srv = TCPServer.new("127.0.0.1", 0)
TCPServer.new("127.0.0.1", TCPServer.port(srv))   # !> IOError: TCPServer.new: Address already in use
```

## port

`TCPServer.port(x)`

待ち受けているポート番号（Integer）。`TCPServer.new` に 0 を渡したときに、実際のポートを知るために使います。閉じたサーバでは `IOError`（`closed stream`）。

```ruby
srv = TCPServer.new("127.0.0.1", 0)
port = TCPServer.port(srv)
p(port >= 1024)                     # => true
p(TCPServer.port(srv) == port)      # => true
TCPServer.close(srv)
```

```ruby error
srv = TCPServer.new("127.0.0.1", 0)
TCPServer.close(srv)
TCPServer.port(srv)                 # !> IOError: TCPServer.port: closed stream
```

## accept

`TCPServer.accept(x)`

次の接続が来るまで待ち、それを `Socket` として返します。接続は `TCPServer.new` の時点から OS が溜めるので、`accept` を呼ぶ前に相手が接続していても失われません。閉じたサーバでは `IOError`。待ち時間の上限はないので、別の Thread から接続するか、時間を区切るなら `Thread.join(t, limit)` と組み合わせます。

```ruby
srv = TCPServer.new("127.0.0.1", 0)
port = TCPServer.port(srv)
clients = Array.map(Any["a", "b"]) { |name|
  Thread.new {
    s = Socket.connect("127.0.0.1", port)
    Socket.write(s, name + "\n")
    reply = Socket.gets(s)
    Socket.close(s)
    reply
  }
}
served = Any[]
Array.each(clients) { |_|
  c = TCPServer.accept(srv)
  p(c)                              # => #<Socket>
                                    # => #<Socket>
  line = Socket.gets(c)
  if line
    Array.push(served, String.chomp(line))
    Socket.write(c, "hi " + line)
  end
  Socket.close(c)
}
replies = Array.compact(Array.map(clients) { |t| Thread.value(t) })   # Socket.gets は nil かもしれないので、並べ替える前に compact
p(Array.sort(replies))              # => ["hi a\n", "hi b\n"]
p(Array.sort(served))               # => ["a", "b"]
TCPServer.close(srv)
```

```ruby error
srv = TCPServer.new("127.0.0.1", 0)
TCPServer.close(srv)
TCPServer.accept(srv)               # !> IOError: TCPServer.accept: closed stream
```

## close

`TCPServer.close(x)`

待ち受けを止めてポートを離し、nil を返します。既に `accept` した `Socket` はそのまま使えます。もう一度閉じても何も起きません。

```ruby
srv = TCPServer.new("127.0.0.1", 0)
port = TCPServer.port(srv)
p(TCPServer.close(srv))             # => nil
p(TCPServer.close(srv))             # => nil
again = TCPServer.new("127.0.0.1", port)
p(TCPServer.port(again) == port)    # => true
TCPServer.close(again)
```

## ==, !=

`TCPServer.==(x, Any)`

`TCPServer.!=(x, Any)`

2 つの値が同じサーバなら等しい（`!=` はその否定）。`TCPServer.new` の結果はそれぞれ別の値です。TCPServer 以外の値とは等しくなく、関数形でも false になります（エラーにはなりません）。

```ruby
srv = TCPServer.new("127.0.0.1", 0)
other = TCPServer.new("127.0.0.1", 0)
p(srv == srv)                       # => true
p(srv == other)                     # => false
p(srv != other)                     # => true
p(TCPServer.==(srv, 1))             # => false
TCPServer.close(srv)
TCPServer.close(other)
```

# Ruby との違いと未対応のもの

Sake の構文は Ruby のものですが、Ruby の書き方のいくつかは静的エラーになり、別の書き方に置き換えます。この付録は、その置き換えを 1 枚の表にまとめ、表の下で理由を述べます。Ruby で書いて静的エラーが出たら、まずこの表を引いてください。各エラーの hint も、表の Sake 側の形を示します。

## Ruby から Sake へ

表の各行は、Ruby の書き方（左）、Sake での書き方（中）、その一言の理由（右）です。理由の詳しい説明と例は表の下の各節にあります。

| Ruby | Sake | 理由 |
|---|---|---|
| `s.upcase` | `String.upcase(s)` | 操作に型を書く |
| `p.x`, `p.x = v` | `Point.x(p)`, `p.Point.x = v`。関数の中では `@x`, `@x = v` | フィールドの読み書きも型を名乗る |
| `x.nil?` | `x == nil` | 値へのメソッド呼び出しは無い |
| `def self.f` | `def f`。module では `module_function` | 名前空間に 1 つの名前は 1 つの関数 |
| `class B < A`（継承） | `class B < A`（A の定義の書き写し。部分型ではない） | 呼び出し先は静的 |
| `attr_reader :x` | `attr_reader x` | フィールド名は裸 |
| `def initialize(x) = @x = x` | `C.new(x)` が格納する。`initialize(c)` は検査と変換だけ | 引数は新しいインスタンス |
| `@items = []`（既定値） | `initialize` の中で `@items = Any[]` | フィールドの既定値は無い |
| `Data.define` | `Struct.new` | クラスは可変 |
| `[1, 2]`（伸びる配列） | `Any[1, 2]`。`[1, 2]` は Tuple（長さ固定） | リテラルの形が型を決める |
| `{a: 1}`（Hash） | `Hash.of(a: 1)`。`{a: 1}` は Record | 同上 |
| `%w[a b]`, `%i[a b]` | `String["a", "b"]`, `Symbol[:a, :b]` | 未決（Tuple か Array か） |
| `PI = 3.14` | `def pi = 3.14`。表は `once { ... }` | 値の定数は無い |
| `Math::PI`, `ARGV`, `$stdout` | `Math.PI`（`Math::PI` も可）、`ARGV`、`IO.stdout` | 操作として読む |
| `case x when Integer` | `case x in Integer` | `===` は無い |
| `for x in xs` | `Array.each(xs) { \|x\| }` | 反復は操作 |
| `$1`, `$~` | `m = String.match(s, re)` の後 `m[1]` | グローバル変数は無い |
| `proc`, `lambda`, `->`, `&:sym`, `method(:f)` | 無し。ブロックは `yield` か `&b` で渡すだけ | ブロックは第二級 |
| `obj.send(:f)`, `define_method`, `method_missing`, `eval` | 無し | 呼び出し先は静的 |
| `g(**opts)` | 無し。Hash を位置で渡す | 設計判断中（D11） |
| `rescue A` で A の子クラスも捕まえる | `rescue M`（型が include したモジュール） | `class B < A` は書き写し |
| `1 + money` | Money に `coerce(m, other)` を定義 | 左のオペランドが決める |

### 操作に型を書く

Sake では型を名乗るのは操作だけです。`s.upcase` のような値へのメソッド呼び出しは静的エラーで、検査器は `String.upcase(s)` を hint で示します（`s.strip.upcase` には連鎖の形 `String.strip(s).upcase`）（[プログラムの構造と名前解決](02-program.md)）。フィールドの読み書きも同じで、`p.x` は `Point.x(p)`、`p.x = v` は `p.Point.x = v` です。クラスの関数の中では `@x` が第 1 引数のフィールド `x` を指します（[クラス](07-classes.md)）。

```ruby
Point = Struct.new(:x, :y)
class Point
  def shift(pt, d)
    @x = @x + d          # Point.set_x(pt, Point.x(pt) + d)
    @x
  end
end
pt = Point.new(1, 2)
p(Point.x(pt))           # => 1
pt.Point.x = 5
p(Point.shift(pt, 1))    # => 6
p(pt)                    # => #<struct Point x=6, y=2>
```

`x.nil?` も値へのメソッド呼び出しなので同じエラーになり、hint は `x == nil` を示します。

### クラス

プログラムが定義する型はクラスです。`class C` に `attr_*` の行で宣言しても、略記の `Struct.new(:x, :y)` で作っても同じものです。Ruby の class と違う点は次のとおりです（[クラス](07-classes.md)）。

- **`def self.f` は書かない。** Sake に `self` は無く、`class C` の中の `def f` がそのまま `C.f` です。Ruby のクラスメソッドもインスタンスメソッドも、Sake では同じ `def f` になります。module では `module_function` を書きます。
- **継承は無い。** `class B < A` は A の定義（フィールド、関数、include）を B に書き写す略記です。その後 A と B は無関係な型で、B の値を `A.f(b)` に渡すのは型エラーです。
- **フィールド名は裸。** `attr_reader :x` は「`:` を付けずに `x` と書く」というエラーになります。
- **`initialize` は値を受け取らない。** `C.new(x)` がフィールドを格納した後、`def initialize(c)` が新しいインスタンスを受けて走ります。Ruby の `def initialize(x) = @x = x` は、インスタンス自身を自分のフィールドに入れることになるので静的エラーです。
- **既定値は `initialize` で。** `attr_reader items = Any[]` はエラーで、最初の値は `initialize` の中で `@items = Any[]` と設定します。`C.new` はそのフィールドを省略できます。
- **`Data.define` は無い。** Sake のクラスは可変なので、Ruby の `Struct` に当たる `Struct.new` を使います。

```ruby
class A
  attr_reader x
  def double(a) = @x * 2
end
class B < A              # A の x と double を B に書き写す
  attr_reader y
end
b = B.new(1, 2)
p(B.double(b))           # => 2
p(b)                     # => #<struct B x=1, y=2>
```

```ruby error
class Bag
  attr_reader name, items
  def initialize(x) = @items = x    # !> `@items = x` stores the new Bag in its own field: `x` is the instance, not a value
end
```

### リテラルと定数

リテラルは形で型が決まります（[値と型](03-values.md)）。

- **Ruby の `Array[1, 2]`、`Hash[...]`、`Set[...]` は、Sake では Array の Array、Hash の Array、Set の Array** です。どの T でも `T[...]` は T の Array だからです。何でも入る Array は `Any[...]`、Hash は `Hash.of(k => v)` か `Hash.new`、Set は `Set.of(a, b)` か `Set.new(xs)` で作ります。
- **`[1, 2]` は Tuple** で、長さが固定です。伸びる配列は `Any[1, 2]`、空なら `Any[]` と書きます。Tuple を `Array.push` に渡すと、`Any[...]` と書く hint 付きの型エラーです。
- **`{a: 1}` は Record** で、`Hash.of(a: 1)` が Hash です。Record のフィールドはパターン `r => {a:}` で読みます。
- **`%w[a b]` と `%i[a b]` は未対応** です。Tuple にするか Array にするかが決まっていません。`String["a", "b"]`、`Symbol[:a, :b]` と書くと、要素型付きの Array になります。
- **値の定数は無い。** `PI = 3.14` は静的エラーで、hint は `def pi = 3.14` を示します。計算して保持したい表は `def table = once { ... }` です（[関数とブロック](04-functions.md)）。定数に代入できるのは `Struct.new` と `Exception.new` だけです。
- **組み込みの定数は操作。** `Math.PI`、`ARGV`、`IO.stdout` のように呼びます。`Math::PI` など組み込みの数個は Ruby の形でも読めます。`$stdout` のようなグローバル変数はありません。

```ruby
t = [1, 2]
xs = Any[1, 2]
Array.push(xs, 3)
p(t, xs)                 # => [1, 2]
                         # => [1, 2, 3]
h = Hash.of(a: 1)
h[:b] = 2
p(h)                     # => {a: 1, b: 2}
def pi = 3.14
p(pi, Math.PI)           # => 3.14
                         # => 3.141592653589793
```

```ruby error
xs = [1, 2]
Array.push(xs, 3)        # !> Array.push: argument 1 must be Array, but is [Integer, Integer] [type]
```

### 制御と反復

- **`case`/`when` は無く、`case`/`in`** を使います。Ruby の `when` はレシーバで `===` をディスパッチしますが、Sake には `===` がありません。`case x in Integer` は型で分岐し、検査器が網羅性を見ます（[制御構造とパターン](06-control.md)）。
- **`for` は無く、操作で反復します。** `Array.each(xs) { |x| ... }`、`Range.each(1..3) { |i| ... }` のように、要素を渡すのは Array や Range の操作です（[関数とブロック](04-functions.md)）。
- **`$1`、`$~` は無い。** 一致を変数に保って読みます: `m = String.match(s, re)` の後、`m` が nil でなければ `m[1]`。

### ブロックと動的な機能

- **ブロックは第二級です。** 関数に渡して `yield` で呼ぶか、`&b` で次の関数に渡すだけで、変数に格納できません。`proc`、`lambda`、`->`、`method(:f)` は無く、`&:sym` も渡せません（[関数とブロック](04-functions.md)）。
- **呼び出し先は静的です。** `send`、`define_method`、`method_missing`、`eval` はありません。`eval` は「静的解析を無効にする」というエラーになります。
- **キーワードの受け渡し。** `def f(**opts)` で集めることはできますが、`g(**opts)` と次の関数に渡すことはできません（`**` is not supported）。Hash を位置引数で渡します。設計判断 D11 として開いています。

### 例外

`rescue A, B => e` は列挙した型を捕まえます（[例外とエラー](08-exceptions.md)）。`class MyErr < StandardError` と書いても MyErr は StandardError の部分型ではなく、`<` は書き写しなので、`rescue A` は `class B < A` を捕まえません。まとめて捕まえるには、型にモジュールを include させて `rescue M` と書きます。組み込みの型は Ruby の親子関係のとおりです（`rescue IndexError` は KeyError も捕まえる）。ただし `rescue => e`、`rescue StandardError => e`、`rescue Exception => e` の 3 つは、Ruby の「どの例外も」という意味を保って、rescue できるすべての例外を捕まえます。

```ruby
class MyErr < StandardError
end
begin
  raise MyErr, "boom"
rescue KeyError, IndexError => e
  p(1)
rescue MyErr => e
  p(Exception.message(e))    # => "boom"
end
```

### 演算子

`a + b` は `Arithmetic.+(a, b)` の略記で、左のオペランドの型で解決されます（[演算子と添字](05-operators.md)）。`1 + money` は Integer でディスパッチするので、Money の `+` には届きません。Ruby と同じプロトコルで、Money に `coerce(m, other)` を定義して `[left, right]` の Tuple を返すと、組を変換してから演算子が走ります。

```ruby
class Money
  include Arithmetic
  attr_reader cents
  def +(a, b) = Money.new(@cents + Money.cents(b))
  def coerce(m, other) = [Money.new(other * 100), m]
end
m = Money.new(50)
p(2 + m)                 # => #<struct Money cents=250>
```

## 未対応のもの

次はいずれも静的に拒否され、「not supported」のエラーになります。多くは設計判断を待っています。

- **Record のフィールドへの書き込み。** `r[:a] = 2` は Record を添字できないというエラーです。読むのはパターン `r => {a:}` です。
- **型スコープ `Integer.(a + b)`。**
- **`case`/`when`。** `case`/`in` を使います。
- **`%w[]`、`%i[]`。** Tuple か Array か未決です。
- **`for`。** 今のところ予定なし。`Range.each(1..3) { |i| ... }` のような操作で反復します。
- **パターンの他の形。** Tuple パターンの `*rest`、find パターン、ピン `^x`、ガード `in Integer if c`。使えるパターンは[制御構造とパターン](06-control.md)にあります。
- **第一級のブロック。** ブロックの格納、`proc`、`lambda`。
- **`g(**opts)`。** 集めたキーワードを次に渡すこと。
- **`begin ... end while`。** `while` を先に書きます。

## 設計の資料

- `DESIGN.md`（日本語）: 設計の経緯と各決定の理由。
- `docs/comparison.md`（日本語）: Sake の新規性。軸ごとに Elm・Crystal・Rust・Elixir・TypeScript・Clojure や型推論の研究と比べ、何が新しく何が既存かを判定する。
- `TODO.md`: 開いている課題と設計判断（D1〜D13）。
- `experiments/`: 各実験の方法・結果・限界（README 付き）。
