Effect 的 Filter 除了 catchFilter 还能用在哪?

我写好一个 Filter 之后第一反应是顺手传给 Option.filter 或 Stream.filter,结果类型检查直接报错。更危险的是绕过类型检查:Filter 返回的 Result 总是 truthy,所有元素都会「通过」。

Filter 能复用在 filterMap 一族和 Stream.catchFilter 上;Option.filter 与 Stream.filter 收的是布尔谓词,要用就先 Filter.toPredicate 降级。

Filter 本质是 (input) => Result<Pass, Fail>,通过时可以变换值,所以它天然对应「过滤加映射」,而不是「只过滤」。Filter 的定义与 catchFilter 的用法见 Effect.catchFilter 怎么同时匹配并提取错误?。

哪些 API 可以直接收 Filter?

我验证过的复用点:

  • Array.filterMap(array, filter):对数组做过滤加变换。用主文章里的 evenHalf(偶数折半,奇数不通过),[1,2,3,4] 得到 [1, 2]。
  • Option.filterMap(option, filter):通过时是 Some,否则 None。
  • Stream.filterMap(filter):流上的同一语义。
  • Stream.catchFilter(filter, handler):流的错误恢复版本。

哪些 API 收的是谓词,不是 Filter?

Option.filter 和 Stream.filter。它们收布尔谓词。如果传 Filter,类型检查会报错;一旦绕过类型检查,Filter 返回的 Result 总是 truthy,会让所有元素「通过」。

要在这两处用 Filter,有两条路:先用 Filter.toPredicate 降级成谓词,或者改用 filterMap。Filter.toOption、Filter.toResult 可以把它降级成 Option 或 Result,我验证过 Filter.toOption(...) 通过时是 Some。

该降级还是该换成 filterMap?

如果你需要 Filter 提取出来的值,用 filterMap,因为降级成谓词会丢掉变换结果。如果你只需要「是否通过」,Filter.toPredicate 够用。我自己倾向前者,因为判断和提取只写一次,这正是 Filter 存在的理由。

以上基于 effect@4.0.5。Array.filterMap 配 evenHalf 得到 [1, 2]、Filter.toOption 通过时为 Some,以及 Option.filter / Stream.filter 收谓词而非 Filter(类型检查会报错),这几点本地验证过。Option.filterMap 与 Stream.filterMap / Stream.catchFilter 的行为我没有逐个运行,请自己用编译器确认。「该降级还是该换成 filterMap」的取舍是我的推论。