我想用 Python 实现类似于这个 OCaml 的东西:
let example = fun v opt_n ->
let fltr = fun i -> i mod 2 = 0
let fltr = match opt_n with
| None -> fltr
| Some n -> fun i -> i mod n = 0 && fltr(n)
fltr v
这很容易组合/扩展,我可以在运行时添加任意数量的谓词。这当然是一个简化的示例,在现实生活中,我有许多可选的包含/排除集,以及用于成员资格的谓词检查。
在 Python 中以简单的方式执行此操作会失败:
def example(v: int, opt_n=None):
"""
doesn't work!
"""
# doesn't need to be a lambda, an explicitely defined function fails too
fltr = lambda i: i % 2 == 0
if opt_n is not None:
# fails miserably -> maximum recursion depth exceeded
fltr = lambda i: fltr(i) and i % opt_n == 0
return fltr(v)
example(10, 5)
这很烦人,因为似乎fltr
只能在作业的左侧出现一次,所以我必须fltr
在之后的每种情况下内联首字母:
def example(v: int, opt_n=None, opt_m=None):
"""annoying but works"""
fltr = None
# some inital filters
pred_0 = lambda _: True # do some real checks ...
pred_1 = lambda _: True # do some real checks ...
if opt_n is not None:
# fltr is inlined, only appears on left side, now it works
fltr = lambda i: pred_0(i) and pred_1(i) and opt_n % 2 == 0
if opt_m is not None:
# much repetition
fltr = lambda i: pred_0(i) and pred_1(i) and opt_n % 3 == 0
if fltr is None:
# inlined again
fltr = lambda i: pred_0(i) and pred_1(i)
return fltr(v)
有什么方法可以解决我的混乱,也许我遗漏了一些东西,以及/或者在 Python 中组合谓词的推荐方法是什么?
当你写作时
fltr
在 lambda 表达式中仍然是一个自由变量,并且在调用函数时会被查找;fltr
当你评估 lambda 表达式时,它并不局限于旧的定义。您需要某种方式来进行早期绑定;一种选择是将的当前值绑定
fltr
到 lambda 表达式本地的新变量,即另一个参数:这不是最干净的解决方案。如果您不介意额外的函数调用,您可以定义一个显式的组合函数:
然后使用它将旧的
fltr
与另一个谓词组合起来以生成一个新的过滤器。(我不太了解 OCaml,但
pred_and
有点像在 Haskell 中使用应用函子,例如pred_and = liftA2 (&&)
。)