# 機能設計書 39-Observable

## 概要

本ドキュメントは、F#コアライブラリにおけるObservable（オブザーバブル）モジュールの機能設計を記述する。Observableモジュールは.NETのIObservable<T>/IObserver<T>インターフェースをベースとしたリアクティブプログラミングのための関数群を提供する。

### 本機能の処理概要

**業務上の目的・背景**：従来のイベント駆動プログラミングではイベントハンドラの登録・解除やイベントの合成が煩雑であった。Observableパターン（Reactive Extensions）は、イベントストリームをファーストクラスの値として扱い、関数型プログラミングスタイルで合成・変換・フィルタリングを可能にする。F#のObservableモジュールはこのパターンの基本的な操作を提供する。

**機能の利用シーン**：UIイベントの処理（クリック、キー入力等）、センサーデータのストリーム処理、WebSocketメッセージの処理、リアルタイムデータフィードの購読、非同期イベントチェーンの構築など。

**主要な処理内容**：
1. イベントストリームの変換（map、choose）
2. イベントストリームのフィルタリング（filter、partition）
3. イベントストリームの合成（merge、scan）
4. イベントストリームの分割（split、pairwise）
5. 購読管理（subscribe、add）

**関連システム・外部連携**：.NETのIObservable<T>/IObserver<T>インターフェースと完全互換。.NET Reactive Extensions（Rx）との相互運用が可能。

**権限による制御**：本機能はライブラリ関数群であり、権限による制御は行わない。

## 関連画面

該当なし（コアライブラリ機能であり、画面は持たない）

## 機能種別

リアクティブプログラミング / イベント処理 / ストリーム処理

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| source | IObservable<'T> | Yes | 入力イベントストリーム | - |
| source2 | IObservable<'T> | No | マージ対象の第2ストリーム | - |
| mapping | 'T -> 'U | No | 変換関数 | - |
| chooser | 'T -> 'U option | No | 選択関数 | - |
| predicate | 'T -> bool | No | 述語関数 | - |
| splitter | 'T -> Choice<'U1, 'U2> | No | 分割関数 | - |
| collector | 'State -> 'T -> 'State | No | 蓄積関数 | - |
| callback | 'T -> unit | No | コールバック関数 | - |

### 入力データソース

F#プログラム内のIObservable<'T>実装（Event、Subject等）。

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| 結果 | IObservable<'U> / IObservable<'T> * IObservable<'T> / IDisposable / unit | 各関数に応じた戻り値 |

### 出力先

変換されたIObservable<'U>またはサブスクリプションのIDisposable。

## 処理フロー

### 処理シーケンス

```
1. ソースObservableの受け取り
   └─ IObservable<'T>インターフェース
2. 新しいObservableの構築
   └─ 匿名クラスでIObservable<'U>を実装
   └─ Subscribe時に内部でソースにサブスクライブ
3. イベント発火時の処理
   └─ map/filter等の変換を適用
   └─ 下流のObserverにOnNextで通知
4. 完了/エラー時の処理
   └─ OnCompleted/OnErrorを伝播
```

### フローチャート

```mermaid
flowchart TD
    A[ソースObservable] --> B{操作種別}
    B -->|map| C[変換関数を適用]
    C --> D[新しいObservableを返却]
    B -->|filter| E[述語でフィルタ]
    E --> D
    B -->|merge| F[2つのストリームを統合]
    F --> D
    D --> G[Subscribe]
    G --> H[IDisposableを返却]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-39-1 | 例外安全 | 変換関数内の例外はOnErrorで捕捉・伝播 | map/choose等の変換時 |
| BR-39-2 | 停止伝播 | OnError/OnCompleted後はOnNextを呼び出さない | ストリーム終了時 |
| BR-39-3 | 購読解除 | IDisposable.Disposeで購読を解除 | リソースクリーンアップ時 |
| BR-39-4 | merge完了 | mergeは両方のソースがOnCompletedしたら完了 | merge使用時 |

### 計算ロジック

- map: 各イベントに変換関数を適用
- filter: 述語を満たすイベントのみを通過
- scan: 状態を蓄積しながら各イベントを処理
- pairwise: 連続する2つのイベントをペアにして出力

## データベース操作仕様

該当なし（メモリ上のデータ操作のみ）

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| OnError伝播 | 例外伝播 | ソースObservableがOnErrorを呼び出した場合 | OnErrorハンドラで処理 |
| 変換例外 | 例外伝播 | map/choose等の変換関数が例外を投げた場合 | 変換関数内でtry-catchまたはOnErrorで処理 |

### リトライ仕様

該当なし（リトライはアプリケーション層で実装）

## トランザクション仕様

該当なし（イベントストリームは一方向）

## パフォーマンス要件

- 各操作はO(1)の追加オーバーヘッド（イベントごと）
- メモリ使用はアクティブなサブスクリプション数に比例
- pairwise/scanは1要素分の状態を保持

## セキュリティ考慮事項

特になし（メモリ内イベント処理のみ）

## 備考

- F# ObservableモジュールはRxの軽量版として位置づけられる
- より高度な機能が必要な場合はFSharp.Control.Reactive（Rx Wrapper）を使用
- EventモジュールのIEvent<'T>はIObservable<'T>を継承している

---

## コードリーディングガイド

本機能を理解するために参照すべきファイルと、推奨する読み解き順序を以下に示す。

### 推奨読解順序

#### Step 1: 基本構造を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | observable.fs | `src/FSharp.Core/observable.fs` | protect関数とBasicObserver型（14-49行目） |

**読解のコツ**:
- `protect`関数は変換関数の例外をキャッチしてOnErrorに伝播する
- `BasicObserver<'T>`は状態管理付きのIObserver実装
- `stopped`フラグでOnError/OnCompleted後の重複通知を防止

**主要処理フロー**:
1. **14-22行目**: `protect`関数 - try-catchで変換関数を保護
2. **24-49行目**: `BasicObserver<'T>`型 - 停止状態を管理するObserver基底クラス

#### Step 2: 変換関数を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | observable.fs | `src/FSharp.Core/observable.fs` | map関数（51-67行目） |
| 2-2 | observable.fs | `src/FSharp.Core/observable.fs` | choose関数（69-90行目） |
| 2-3 | observable.fs | `src/FSharp.Core/observable.fs` | filter関数（92-94行目） |

**主要処理フロー**:
1. **51-67行目**: `map`関数 - 新しいIObservableを返し、Subscribe時にソースにサブスクライブ
2. **69-90行目**: `choose`関数 - Someの場合のみOnNextを呼び出す
3. **92-94行目**: `filter`関数 - chooseを使って述語フィルタリング

#### Step 3: 合成関数を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | observable.fs | `src/FSharp.Core/observable.fs` | partition関数（96-98行目） |
| 3-2 | observable.fs | `src/FSharp.Core/observable.fs` | scan関数（100-125行目） |
| 3-3 | observable.fs | `src/FSharp.Core/observable.fs` | merge関数（159-214行目） |

**主要処理フロー**:
1. **96-98行目**: `partition`関数 - 述語で2つのストリームに分割
2. **100-125行目**: `scan`関数 - 状態を蓄積しながら変換
3. **159-214行目**: `merge`関数 - 2つのストリームを1つに統合

#### Step 4: ペアワイズ・分割関数を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 4-1 | observable.fs | `src/FSharp.Core/observable.fs` | pairwise関数（135-157行目） |
| 4-2 | observable.fs | `src/FSharp.Core/observable.fs` | split関数（216-229行目） |

**主要処理フロー**:
1. **135-157行目**: `pairwise`関数 - 連続するイベントをペアに
2. **216-229行目**: `split`関数 - Choice型で2つのストリームに分割

### プログラム呼び出し階層図

```
ユーザーコード
    │
    ├─ Observable.map mapping source
    │      └─ { new IObservable<'U> with Subscribe(observer) }
    │             └─ source.Subscribe({ new BasicObserver<'T>() with ... })
    │                    └─ protect (fun () -> mapping v) observer.OnNext observer.OnError
    │
    ├─ Observable.filter predicate source
    │      └─ Observable.choose (fun x -> if predicate x then Some x else None) source
    │
    ├─ Observable.merge source1 source2
    │      └─ { new IObservable<'T> with Subscribe(observer) }
    │             ├─ source1.Subscribe(observer1)
    │             └─ source2.Subscribe(observer2)
    │                    └─ 両方完了したらObserver.OnCompleted()
    │
    └─ Observable.subscribe callback source
           └─ source.Subscribe(callback)
                  └─ IDisposableを返却
```

### データフロー図

```
[ソース]                      [変換]                           [出力]

IObservable<'T> ─────────▶ map(f) ─────────────────────▶ IObservable<'U>
                              │
                              └──▶ 各OnNext(x) → OnNext(f x)

IObservable<'T> ─────────▶ filter(p) ─────────────────▶ IObservable<'T>
                              │
                              └──▶ 各OnNext(x) → p(x)ならOnNext(x)

IObservable<'T>  ┐
                 ├───────▶ merge ─────────────────────▶ IObservable<'T>
IObservable<'T>  ┘               │
                                 └──▶ 両方のOnNextを統合

IObservable<'T> ─────────▶ pairwise ──────────────────▶ IObservable<'T * 'T>
                              │
                              └──▶ OnNext(x1), OnNext(x2) → OnNext(x1, x2)
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| observable.fs | `src/FSharp.Core/observable.fs` | ソース | Observableモジュールの実装 |
| observable.fsi | `src/FSharp.Core/observable.fsi` | シグネチャ | Observableモジュールのシグネチャ定義 |
| event.fs | `src/FSharp.Core/event.fs` | ソース | Event型の実装（IObservable実装） |
