ヒストリア290404 views
世界の国564381 views
教育149497 views
中学理科1630528 views
小学算数1200301 views
数学講師2885293 views
高校物理160088 views
高校日本史190552 views
高校化学2924053 views
高校国語788290 views

Python でモナド的パターンの実装(Maybe, Either)

関数型プログラミングの 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 の乱用を避け、エラー処理を宣言的に記述できます。