りんご198413 views
いろは2995081 views
中学社会667518 views
高校国語786382 views
高校生物550332 views
LaTeX958597 views
世界の国561710 views
高校化学2916128 views
教育149096 views
小学理科718021 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 の乱用を避け、エラー処理を宣言的に記述できます。