# 演算子リファレンス

## 概要

> **PHILOSOPHY.md -- I.** 深く考えずに適当にぶちこんでけ

Taida Langの演算子は**2つのカテゴリ**に分類されます。

### Taida固有演算子（10種）

Taidaの言語設計において特別な意味を持つ演算子です。「演算子は10種のみ」という哲学に基づき、これらは覚えるべき最小限のセットです。

| # | 演算子 | 名称 | 用途 |
|---|--------|------|------|
| 1 | `=` | 定義 | 型・関数・エラー天井の定義 |
| 2 | `=>` | 右ぶちこみ | パイプライン・代入（左から右へ） |
| 3 | `<=` | 左ぶちこみ | 代入・関数適用（右から左へ） |
| 4 | `]=>` | 前方アンモールディング | `solidify` 後の値から `unmold` で取り出す（左から右） |
| 5 | `<=[` | 後方アンモールディング | `solidify` 後の値から `unmold` で取り出す（右から左） |
| 6 | `\|==` | エラー天井 | エラーをキャッチして処理 |
| 7 | `\|` | 条件ガード | 条件分岐の区切り |
| 8 | `\|>` | 条件抽出 | 条件分岐の値取り出し |
| 9 | `>>>` | インポート | モジュールの読み込み |
| 10 | `<<<` | エクスポート | シンボルの公開 |

### その他の演算子

Taida固有演算子とは別カテゴリの、一般的なプログラミング言語にも存在する演算子です。これらは「10種の演算子」のカウントには含まれません。

| 種類 | 演算子 | 用途 |
|------|--------|------|
| 算術 | `+` `-` `*` | 数値演算（単項 `-` を含む） |
| 比較 | `==` `!=` `<` `>` `>=` | 比較（真偽値を返す） |
| 論理 | `&&` `\|\|` `!` | 論理演算（短絡評価） |

> **注意**: Taida に除算 (`/`) と剰余 (`%`) 演算子はありません。`Div[x, y]()` と `Mod[x, y]()` モールドを使用してください。

> **注意**: 比較演算子に `<=`（以下）は存在しません。`<=` は左ぶちこみ演算子として使用されるためです。「以下」を表現するには `!(x > n)` または `x < n \|\| x == n` を使用してください。

### 全演算子の一覧表

| カテゴリ | 種類 | 演算子 | 個数 |
|---------|------|--------|------|
| Taida固有 | ぶちこみ | `=` `=>` `<=` | 3 |
| Taida固有 | アンモールディング | `]=>` `<=[` | 2 |
| Taida固有 | 制御 | `\|==` `\|` `\|>` | 3 |
| Taida固有 | モジュール | `>>>` `<<<` | 2 |
| その他 | 算術 | `+` `-` `*` | 3 |
| その他 | 比較 | `==` `!=` `<` `>` `>=` | 5 |
| その他 | 論理 | `&&` `\|\|` `!` | 3 |

---

## 算術演算子

数値に対する基本的な演算を行います。優先順位はRustに準拠します。

| 演算子 | 説明 | 例 |
|--------|------|-----|
| `+` | 加算 | `3 + 5` → `8` |
| `-` | 減算 | `10 - 3` → `7` |
| `*` | 乗算 | `4 * 5` → `20` |
| `-` | 単項マイナス | `-5` |

### 除算と剰余

除算と剰余は `Div[x, y]()` と `Mod[x, y]()` モールドで行います。結果は Lax で返されます。

```taida
Div[10, 3]() ]=> result   // 3
Div[10, 0]() ]=> result   // 0 (ゼロ除算: Lax のデフォルト値)

Mod[10, 3]() ]=> result   // 1
Mod[10, 0]() ]=> result   // 0 (ゼロ除算: Lax のデフォルト値)
```

> `/` 演算子と `%` 演算子は Taida には存在しません。`Div[x, y]()` と `Mod[x, y]()` モールドで行います。

---

## 比較演算子

2つの値を比較し、`Bool` を返します。

| 演算子 | 説明 | 例 |
|--------|------|-----|
| `==` | 等価 | `x == y` |
| `!=` | 非等価 | `x != y` |
| `<` | 小なり | `x < y` |
| `>` | 大なり | `x > y` |
| `>=` | 以上 | `x >= y` |

> **注意**: `<=`（以下）は左ぶちこみ演算子と重複するため、比較演算子としては存在しません。「以下」を表現するには `<` と `==` を組み合わせてください。

```taida
// 「以下」の表現
is_small <= x < 10 || x == 10

// または否定を使う
is_small <= !(x > 10)
```

---

## 論理演算子

真偽値に対する論理演算を行います。短絡評価を行います（JS準拠）。

| 演算子 | 説明 | 短絡評価 |
|--------|------|----------|
| `&&` | 論理AND | 左がfalseなら右を評価しない |
| `\|\|` | 論理OR | 左がtrueなら右を評価しない |
| `!` | 論理NOT | - |

```taida
// AND: 両方trueの場合のみtrue
result <= x > 0 && y > 0

// OR: どちらかがtrueならtrue
result <= x == 0 || y == 0

// NOT: 真偽値を反転
result <= !is_valid

// 短絡評価の活用
safe <= x > 0 && x + y > 10
```

---

## ぶちこみ演算子

### `=>` 右ぶちこみ

左の値を右に渡します。

```taida
// 関数への適用
5 => add(3, _) => result  // result: 8

// 変数への代入
processData(input) => output

// パイプライン
data => filter(_) => map(_) => result
```

### `<=` 左ぶちこみ

右の値を左に渡します。変数への代入に使います。

```taida
// 変数への代入
x <= 42
name <= "Misato"

// 型のインスタンス化
pilot <= Pilot(name <= "Rei", age <= 14)

// 関数適用の結果を代入
result <= add(10, x)
```

> **注意**: `<=` は変数への単一代入のみに使用できます。`result <= f() <= g() <= data` のような `<=` のチェーン（逆方向パイプライン）は現在サポートされていません。逆方向のデータフローが必要な場合は、`=>` の順方向パイプラインまたは中間変数を使用してください。

### 単一方向制約（ぶちこみ演算子）

一つの文（statement）内で、`=>` と `<=` を混在させることは禁止されています。

**形式定義：**
- 文 S 内に出現するぶちこみ演算子の集合を `Ops(S)` とする
- `{=>} ⊆ Ops(S)` かつ `{<=} ⊆ Ops(S)` のとき、文 S はコンパイルエラーとなる
- ただし `=`（定義演算子）はこの制約の対象外である

```taida
// OK: 単一方向
data => filter(_) => map(_) => result

// OK（仕様上有効だが、現在のパーサーは <= チェーン未対応。将来対応予定）:
// result <= map(_) <= filter(_) <= data

// NG: 方向混在（コンパイルエラー）
data => filter(_) <= result
// エラー E0301: 単一方向制約違反
//   一つの文内で => と <= を混在させることはできません
//   ヒント: data => filter(_) => result に書き換えてください
```

> **注意**: `<=` のチェーン（`result <= f() <= g() <= data` のような2段以上の連鎖）は仕様上有効ですが、現在のパーサーでは単一の `<=` 代入のみサポートしています。逆方向のデータフローが必要な場合は `=>` の順方向パイプラインまたは中間変数を使用してください。

### `=` 定義

型、関数、エラー天井などを定義します。

```taida
// 型定義
Pilot = @(name: Str, age: Int)

// 関数定義
add x: Int y: Int =
  x + y
=> :Int

// モールディング型定義（Mold基底クラスから継承）
Mold[T] => Result[T, P <= :T => :Bool] = @(throw: Error)

// エラー天井定義
|== error: MyError =
  "Error: " + error.message
=> :Str
```

---

## 制御演算子

### `|==` エラー天井

エラーをキャッチして処理します。

```taida
|== error: ErrorType =
  | error.type == "NotFound" |> defaultValue
  | _ |> handleError(error)
=> :ReturnType

// この下でthrowが発生する可能性のある処理
riskyOperation()
```

### `|` `|>` 条件分岐

条件に基づいて値を選択します。

```taida
// 基本形（_ はプレースホルダ）
| condition |> valueIfTrue | _ |> valueIfFalse

// 複数条件
| x > 10 |> "large"
| x > 5 |> "medium"
| _ |> "small"

// パターンマッチ
| status == "success" |> handleSuccess()
| status == "error" |> handleError()
| _ |> handleUnknown()
```

### throw

エラーを発生させます。`throw()` メソッドは Error型を継承した型のインスタンスのみが持ちます。

```taida
// エラー型の定義（Errorを継承）
Error => ValidationError = @(field: Str)

// 条件付きthrow
| condition |> ValidationError(type <= "ValidationError", message <= "Something wrong", field <= "input").throw()

// 変数に入れてthrow
err <= ValidationError(type <= "ValidationError", message <= "Invalid input", field <= "data")
err.throw()
```

---

## モジュール演算子

### `>>>` インポート

モジュールをインポートします。

```taida
// ローカルファイル（シンボル指定）
>>> ./utils.td => @(helper)

// シンボル省略（全エクスポートを取り込む）
>>> ./utils.td

// バージョン指定（packages.tdm のみ）
>>> author/package@a.3 => @(funcA)

// エイリアス
>>> ./other.td => @(add, subtract => sub)
```

`=> @(symbols)` を省略すると、対象モジュールの全エクスポートを取り込みます。名前衝突を避けるため、明示的なシンボル指定を推奨します。

バージョン付きインポート（`@a.3` 等）は packages.tdm でのみ使用可能です。

### `<<<` エクスポート

シンボルをエクスポートします。通常の `.td` ファイルでは複数行の `<<<` が許可されます。

```taida
// 複数シンボル
<<< @(add, subtract, Point)

// 複数行に分割（通常の .td のみ、packages.tdm では1行のみ）
<<< @(add, subtract)
<<< @(Point)

// 単一シンボル
<<< add

// ワンライナー
<<< double x: Int = x * 2 => :Int
```

packages.tdm ではバージョン付き `<<<` が使用され、1行のみ許可されます: `<<<@a.3 @(hello, greet)`

---

## 特殊記号

### `_` プレースホルダ

3つの用途があります。

```taida
// 1. パターンマッチのワイルドカード（「それ以外の全て」）
| _ |> defaultValue

// 2. ラムダ関数の宣言
_ x = x * 2

// 3. パイプラインでの前ステップの値
data => Trim[_]() => output
```

### 空スロット部分適用

関数呼び出しの引数を空にすると部分適用になります。

```taida
add5 <= add(5, )     // 第2引数が穴
double <= multiply(, 2)  // 第1引数が穴
```

### `@(...)` ぶちパック

構造化データを表現します。

```taida
// 値の作成
pilot <= @(name <= "Misato", age <= 29)

// 型定義
Pilot = @(name: Str, age: Int)
```

### 確定済み意味論

以下は `taida check` が前段ゲートとして強制する確定済み意味論です。

#### `_` の3用途（これ以外は禁止）

`_` は以下の3つの文脈でのみ使用できます。

1. **パターンマッチのワイルドカード**: `| _ |> defaultValue` — 「それ以外の全て」
2. **ラムダ関数の宣言**: `_ x = x * 2` — 無名関数の名前位置
3. **パイプラインでの前ステップの値**: `data => Trim[_]() => output` — パイプライン内の前ステップ結果

**禁止**: 関数呼び出しの引数に `_` を渡して部分適用する旧構文 `add(5, _)` は `[E1502]` で拒否されます。空スロット `add(5, )` を使用してください。

#### 空スロット部分適用

関数呼び出しの引数位置を空にすると部分適用になります。

- `add(5, )` — 第2引数が穴。通常の関数呼び出しのみに適用
- TypeDef やモールドのインスタンス化には使用できません（`[E1503]` / `[E1504]` で拒否）

#### 関数オーバーロード禁止

同じ名前の関数を異なる引数パターンで複数定義すること（オーバーロード）は禁止です。`[E1501]` で拒否されます。

#### 同一スコープ重複定義禁止

同一スコープ内で同じ名前の変数・関数・型を再定義することは禁止です。`[E1501]` で拒否されます。異なるスコープでのシャドーイングは許可されます。詳細は `docs/reference/scope_rules.md` を参照してください。

### `@[...]` リスト

リストを表現します。

```taida
numbers <= @[1, 2, 3, 4, 5]
names <= @["Misato", "Rei"]
empty <= @[]
```

### `><` ゴリラリテラル

プログラムを即時終了させます。回復不能な前提条件の違反に使います。`|==` エラー天井ではキャッチできません。

```taida
| config.dbUrl == "" |> ><   // DB接続先なしは致命的
| config.port < 0 |> ><     // 不正なポートも致命的
```

Gorillax モールドの unmold 失敗時も同様にゴリラが発動し、プログラムが即時終了します。

### `unmold()` アンモールディング（メソッド形式）

`solidify` 後の値に対して `unmold` を実行し、取り出し値を返します。

```taida
lax <= Div[10, 3]()

// unmold()で値を取得（メソッド形式）
x <= lax.unmold()  // 3

result <=
  | x > 10 |> "large"
  | _ |> "small"
```

---

## アンモールディング演算子

### `]=>` 左アンモールディング

`solidify` 後の値に `unmold` を適用し、右側の変数に代入します。

```taida
lax <= Div[10, 3]()

// ]=> で値を取得して代入
lax ]=> x  // x に 3 が代入される

// リスト操作モールディング型との組み合わせ
Map[numbers, _ n = n * 2]() ]=> doubled
Filter[items, _ x = x > 10]() ]=> filtered

// チェーン
Filter[numbers, _ x = x > 2]() ]=> filtered
Map[filtered, _ x = x * 2]() ]=> result
```

### `<=[` 右アンモールディング

`]=>` の逆向き。`solidify` 後の値に `unmold` を適用し、左側の変数に代入します。

```taida
lax <= Div[10, 3]()

// <=[ で値を取得して代入
x <=[ lax  // x に 3 が代入される

// リスト操作との組み合わせ
doubled <=[ Map[numbers, _ n = n * 2]()
filtered <=[ Filter[items, _ x = x > 10]()
```

### 単一方向制約（アンモールディング演算子）

一つの文（statement）内で、`]=>` と `<=[` を混在させることは禁止されています。

**形式定義：**
- 文 S 内に出現するアンモールディング演算子の集合を `UnmoldOps(S)` とする
- `{]=>} ⊆ UnmoldOps(S)` かつ `{<=[} ⊆ UnmoldOps(S)` のとき、文 S はコンパイルエラーとなる

```taida
// OK: 単一方向
mold ]=> value
value <=[ mold

// NG: 方向混在（コンパイルエラー）
mold ]=> x <=[ other
// エラー E0302: 単一方向制約違反
//   一つの文内で ]=> と <=[ を混在させることはできません
```

> **注意**: ぶちこみ演算子（`=>` / `<=`）の単一方向制約とは独立して適用されます。つまり `=>` と `<=[` の共存、`<=` と `]=>` の共存は制約対象外です（これらは異なるカテゴリの演算子です）。

### `unmold()` と `]=>`/`<=[` の使い分け

```taida
// メソッド形式（式の中で使いたい場合）
result <= lax.unmold() + 10

// 演算子形式（代入したい場合）
lax ]=> value
result <= value + 10
```

---

## 演算子の優先順位

優先順位はRustに準拠します（高い順）。

| 優先度 | 演算子 | 結合性 |
|--------|--------|--------|
| 1 | `()` 関数呼び出し、`.` フィールドアクセス | 左から右 |
| 2 | `!` `-`（単項） | 右から左 |
| 3 | `*` | 左から右 |
| 4 | `+` `-` | 左から右 |
| 5 | `<` `>` `>=` | 左から右 |
| 6 | `==` `!=` | 左から右 |
| 7 | `&&` | 左から右 |
| 8 | `\|\|` | 左から右 |
| 9 | `\|` `\|>` 条件分岐 | 左から右 |
| 10 | `]=>` `<=[` アンモールディング | 左から右 |
| 11 | `=>` `<=` ぶちこみ | 左から右 |
| 12 | `\|==` エラー天井 | - |
| 13 | `>>>` `<<<` モジュール | - |

```taida
// 例：優先順位の適用
result <= 1 + 2 * 3      // => 7 (乗算が先)
result <= (1 + 2) * 3    // => 9 (括弧で優先)
result <= x > 0 && y > 0 // 比較が先、その後 &&
```

---

## 一般的なパターン

### 変数定義と関数適用

```taida
// 変数定義
x <= 42

// 関数適用（右ぶちこみ）
x => add(10, _) => result

// 関数適用（左ぶちこみ）
result <= add(x, 10)
```

### 関数呼び出しの引数補完（仕様）

関数引数デフォルトの正式仕様は `docs/design/function_default_args.md` を参照。

要点:

1. 省略された末尾引数は実効デフォルトで補完される
2. 実効デフォルトは `param: Type <= expr` があれば `expr`、なければ型デフォルト
3. 引数過多はコンパイルエラー

```taida
sum3 a: Int b: Int <= 10 c: Int <= 20 =
  a + b + c
=> :Int

sum3(1)  // 31
sum3()   // 30
```

### 条件付き処理

```taida
value <=
  | condition1 |> result1
  | condition2 |> result2
  | _ |> defaultResult
```

### エラー処理

```taida
// エラー型の定義
Error => InvalidInputError = @(input: Str)

processData input =
  |== error: Error =
    handleError(error)
  => :ResultType

  | !isValid(input) |> InvalidInputError(type <= "InvalidInputError", message <= "Bad input", input <= input).throw()
  | _ |> doProcess(input)
=> :ResultType
```

### モジュール構成

```taida
// インポート
>>> ./utils.td => @(helper)

// 処理
result <= helper(data)
// result: 処理結果

// エクスポート
<<< @(myFunction, MyType)
```
