Katharos: Python 的函数式编程与 CSP 风格并发

Katharos 是一个面向 Python 3.13+ 的函数式编程与并发库,它通过显式、可组合且类型安全的数值,取代了隐藏的控制流(例如异常和 None 检查)。通过将代数抽象与消息传递并发模型相结合,Katharos 允许开发者将错误、可选性以及并发通信视为一等公民数值。

代数抽象与类型安全数值

Katharos 实现了核心的函数式编程抽象,以消除样板代码并减少与空值和异常相关的运行时错误。

使用 Maybe 消除 None 检查

而非散落在各处的 if x is None 检查,Katharos 使用 Maybe 类型。这允许在值缺失时对逻辑进行清晰的短路处理。

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  # Returns Just(0.15) or Nothing()

使用 Result 将错误处理视为数值

Katharos 将错误视为数值而非异常。Result 类型允许使用管道操作符 (|) 对错误进行链式调用,其中 Failure 会自动短路剩余的链条。

为了减少手动的 try/except 样板代码,@Result.catch 装饰器可以将抛出特定异常的函数转换为返回 Result 类型的函数,同时保留原始回溯以供调试。

from katharos.types import Result

@Result.catch(ValueError)
def parse_int(s: str) -> int:
    return int(s)

# Returns Success(42) or Failure(ValueError(...))
result = parse_int("42")

其他函数式类型

  • ImmutableList: 提供不可变序列,可以使用 Semigroup 操作符 (@) 进行组合。
  • Algebraic Core: 该库提供了 FunctorApplicativeMonadSemigroupMonoid 的正式实现,以确保不同类型之间的一致性组合。

CSP 风格并发

Katharos 实现了 Go 风格的通信顺序进程 (CSP) 模型用于并发,确保并发任务之间的通信与函数式数据类型一样具有类型安全性。

消息传递与通道

工作任务通过 csp.go 并发启动,并通过类型化的 Channel 进行通信。至关重要的是,从通道接收值会返回一个 Result。这意味着关闭或超时的通道是一个需要进行模式匹配的数值,而不是需要捕获的异常。

from katharos.concurrency.csp import csp

ch = csp.Channel[int](capacity=1)

# Run work concurrently
csp.go(ch.send, 42)

# Receive as a Result value
ch.recv()  # Success(42)

ch.close()
ch.recv()  # Failure(ChannelClosedError(...))

结构化并发

当作为上下文管理器使用时,csp.go 会创建一个结构化并发作用域。程序将在退出该作用域之前合并(join)该块内启动的所有工作,从而防止类似 goroutine 的任务泄漏。

with csp.go:
    csp.go(worker, 1)
    csp.go(worker, 2)
n# Both workers are guaranteed to have finished here

可插拔后端

Katharos 中的所有并发模型都绑定到 BaseThreadingBackend。虽然标准线程是默认选项,但这种抽象允许在单一位置将运行时重新定向到不同的后端。计划在未来的更新中包含基于此相同后端抽象的 Actor 模型。

实现细节与社区反馈

Do-Notation 机制

Katharos 通过 Python 生成器提供 do-notation,以允许命令式的单子(monadic)代码。然而,社区反馈指出,由于 Python 缺乏 call/cc (call-with-current-continuation),针对某些单子(如列表单子)的实现可能涉及重新运行生成器,这可能会将其用途限制在较简单的用例或“玩具”示例中。

"It's probably worth being up front about what your do syntax actually does. A generator is not as general as "do", Python doesn't have call/cc or anything like that."

要求

Katharos 是为 Python 3.13+ 设计的。

Sources