関数型プログラミングの Maybe(Option)と Either(Result)パターンを Python で実装すると、エラー処理を型安全かつ合成可能にできます。
Maybe パターン
値が存在するかしないかを表現します。
from typing import TypeVar, Generic, Callable, Optional from dataclasses import dataclass T = TypeVar("T") U = TypeVar("U") class Maybe(Generic[T]): pass @dataclass class Just(Maybe[T]): value: T @dataclass class Nothing(Maybe[T]): pass def map_maybe(m: Maybe[T], f: Callable[[T], U]) -> Maybe[U]: if isinstance(m, Just): return Just(f(m.value)) return Nothing() def bind_maybe(m: Maybe[T], f: Callable[[T], Maybe[U]]) -> Maybe[U]: if isinstance(m, Just): return f(m.value) return Nothing()
使用例:
def safe_div(a: int, b: int) -> Maybe[float]: if b == 0: return Nothing() return Just(a / b) result = bind_maybe(Just(10), lambda x: safe_div(x, 2)) # Just(value=5.0)
Either パターン
成功と失敗の両方に値を持てます。
from typing import TypeVar, Generic, Callable, Union from dataclasses import dataclass L = TypeVar("L") # Left(エラー) R = TypeVar("R") # Right(成功) class Either(Generic[L, R]): pass @dataclass class Left(Either[L, R]): value: L @dataclass class Right(Either[L, R]): value: R def map_either(e: Either[L, R], f: Callable[[R], U]) -> Either[L, U]: if isinstance(e, Right): return Right(f(e.value)) return e def bind_either( e: Either[L, R], f: Callable[[R], Either[L, U]] ) -> Either[L, U]: if isinstance(e, Right): return f(e.value) return e
使用例:
def parse_int(s: str) -> Either[str, int]: try: return Right(int(s)) except ValueError: return Left(f"Cannot parse '{s}'") result = bind_either( parse_int("42"), lambda x: Right(x * 2) if x > 0 else Left("Must be positive") ) # Right(value=84)
これらのパターンにより、None チェックの連鎖や try-except の乱用を避け、エラー処理を宣言的に記述できます。