HN 日本語サマリー

← 一覧へ戻る
プログラミング

Show HN: Katharos Python向け関数型プログラミングとCSPスタイルの並行処理

Show HN: Katharos Functional programming and CSP-style concurrency for Python (github.com)

24 pointsby kamalf7 コメント

要約

Katharosは、Python向けの関数型プログラミングと並行処理ライブラリです。代数的抽象化と具体的な型を、メッセージパッシング型の並行処理と組み合わせています。エラーや副作用、並行処理の通信を合成可能で型安全な値としてモデル化することで、例外処理やNoneチェックの代わりに、よりクリーンで宣言的なコードを実現します。GoスタイルのCSP並行処理もサポートしており、チャネルのクローズやタイムアウトも例外ではなく値として扱います。

全文翻訳

Katharos Python向けの関数型プログラミングと並行処理ライブラリです。 Functor, Applicative, Monad, Semigroup, Monoidのような代数的抽象化と、Maybe, Result, ImmutableList, IOのような具体的な型を、同じ関数型コアに基づいたメッセージパッシング型の並行処理と組み合わせています。 この二つの部分は一つのアイデアを共有しています。それは、エラー、副作用、並行処理の通信を合成可能で型安全な値としてモデル化することです。 並行処理での値の受け渡しはResultを返します。そのため、「チャネルが閉じられた」ということは、キャッチする例外ではなく、あなたが処理すべきものとなります。 インストール pip install katharos またはuvを使用する ```bash uv add katharos ``` どのようなものか 以前: 散在するNoneチェックと例外処理: ```python user = find_user(user_id) if user is None: return None account = find_account(user) if account is None: return None return account.discount ``` 以後: Nothingでクリーンにショートサーキットするdo-notation: ```python from katharos.types import Maybe from katharos.syntax_sugar import do, DoBlock @do(Maybe) def lookup_discount(user_id: int) -> DoBlock[Maybe, float]: user = yield find_user(user_id) account = yield find_account(user) return account.discount # Just(0.15) または Nothing() ``` 以前: エラーを伝播させるためのネストされたtry/except: ```python def process(raw: str) -> int: try: n = parse_int(raw) except ValueError as e: raise RuntimeError("bad input") from e try: return validate_positive(n) except ValueError as e: raise RuntimeError("bad value") from e ``` 以後: エラーを値として扱い、|で連鎖させる: ```python from katharos.types import Result def process(raw: str) -> Result[Exception, int]: return parse_int(raw) | validate_positive # Failureは自動的にショートサーキットする ``` その他の例 Noneチェックなしでオプション値を処理する: ```python from katharos.types import Maybe result = Maybe[int].Just(5) | (lambda x: Maybe[int].Just(x * 2)) # Just(10) nothing = Maybe[int].Nothing() | (lambda x: Maybe[int].Just(x * 2)) # Nothing() ``` 例外ではなく値としてエラーをモデル化する: ```python from katharos.types import Result def parse_int(s: str) -> Result[ValueError, int]: try: return Result.Success(int(s)) except ValueError as e: return Result.Failure(e) parse_int("42").fmap(lambda n: n * 2) # Success(84) parse_int("??").fmap(lambda n: n * 2) # Failure(...) ``` Result.catchでボイラープレートをスキップする: Result.catchは、例外を発生させる関数を、手動のtry/exceptなしでResultを返す関数に変換します。 宣言された例外タイプのみがFailureとなり、キャッチされた例外はそのトレースバックを保持するため、失敗した行を依然として見つけることができます。 ```python import traceback from katharos.types import Result @Result.catch(ValueError) def parse_int(s: str) -> int: return int(s) parse_int("42") # Success(42) parse_int("??") # Failure(ValueError("invalid literal for int() with base 10: '??'")) failure = parse_int("??") if failure.is_failure(): traceback.print_exception(failure.error) # 完全なトレースバック、失敗した行を指す ``` Semigroup演算子で値を結合する: ```python from katharos.types import ImmutableList ImmutableList([1, 2]) @ ImmutableList([3, 4]) # ImmutableList([1, 2, 3, 4]) ``` Do-notation do-notationは、Maybe, Result, IO, ImmutableList、およびカスタムモナドなど、あらゆるモナドで機能します。 各yieldはモナド値をアンラップします: ```python from katharos.syntax_sugar import do, DoBlock from katharos.types import Result def parse_positive(x: int) -> Result[ValueError, int]: return Result.Success(x) if x > 0 else Result.Failure(ValueError(f"{x} is not positive")) # クリーンで命令型のモナドコード @do(Result) def do_block() -> DoBlock[Result, int]: x: int = yield parse_positive(5) y: int = yield parse_positive(3) return x + y print(do_block()) # Success(8) ``` 並行処理 Katharosは、同じ関数型コア上に構築されたメッセージパッシング型の並行処理を提供し、複数の並行処理モデルの余地があります。 最初に使用可能なモデルはGoスタイルのCSPです。go(Goの`go f(x)`のようなもの)で並行処理で作業を起動し、型付きチャネルを介して通信し、そして(決定的に重要ですが)値を受信するときはResultとして受信します。そのため、閉じられた、またはタイムアウトしたチャネルは、例外ではなくパターンマッチングで処理する値となります。 ```python from katharos.concurrency.csp import csp ch = csp.Channel[int](capacity=1) csp.go(ch.send, 42) # Goの`go f(x)`のように、作業を並行して実行する ch.recv() # Success(42) ch.close() ch.recv() # Failure(ChannelClosedError(...)): クローズは例外ではなく値です ``` コンテキストマネージャーとして使用すると、`go`は構造化された並行処理スコープとなり、ブロックが終了する前にその中で起動されたすべての処理を結合します: ```python from katharos.concurrency.csp import csp with csp.go: # スコープは内部で起動されたすべての作業が完了するのを待つ csp.go(worker, 1) csp.go(worker, 2) # ここで両方のワーカーが完了している ``` すべての並行処理モデルは、スワップ可能な`BaseThreadingBackend`(デフォルトでは標準スレッド)にバインドされており、`csp`ランタイムはそれを自動的に供給するため、単一の場所で作業を異なるバックエンドにリターゲットできます。 追加のモデル(アクターモデルなど)は、同じバックエンド抽象化と、同じResult値を持つ合成可能なスタイルに基づいて計画されています。 ドキュメント 完全なチュートリアル、ハウツーガイド、APIリファレンス、および数学的基礎の説明は katharos.readthedocs.io で入手できます。 ライセンス MIT