我有一个函数 m_chain,它指的是两个bind
未定义unit
的函数。我想将此函数包装在为这些函数提供定义的某些上下文中 - 您可以将它们视为我想为其动态提供实现的接口。
def m_chain(*fns):
"""what this function does is not relevant to the question"""
def m_chain_link(chain_expr, step):
return lambda v: bind(chain_expr(v), step)
return reduce(m_chain_link, fns, unit)
在 Clojure 中,这是通过宏完成的。在 python 中有哪些优雅的方法可以做到这一点?我考虑过:
- 多态性:将 m_chain 转换为引用
self.bind
and的方法self.unit
,其实现由子类提供 - 实现
with
接口,这样我就可以修改环境映射,然后在我完成后清理 - 更改 m_chain 的签名以接受单元并绑定作为参数
- 要求使用 m_chain 由装饰器包裹,该装饰器将做某事或其他事情 - 不确定这是否有意义
理想情况下,我根本不想修改 m_chain,我想按原样使用定义,并且上述所有选项都需要更改定义。这一点很重要,因为还有其他 m_* 函数引用了在运行时提供的附加函数。
我如何最好地构建它,以便我可以很好地传递绑定和单元的实现?尽管实现复杂,但 m_chain 的最终用法必须非常易于使用,这一点很重要。
编辑:这是另一种可行的方法,它非常丑陋,因为它需要将 m_chain 柯里化为没有参数的函数。但这是一个最小的工作示例。
def domonad(monad, cmf):
bind = monad['bind']; unit = monad['unit']
return cmf()
identity_m = {
'bind':lambda v,f:f(v),
'unit':lambda v:v
}
maybe_m = {
'bind':lambda v,f:f(v) if v else None,
'unit':lambda v:v
}
>>> domonad(identity_m, lambda: m_chain(lambda x: 2*x, lambda x:2*x)(2))
8
>>> domonad(maybe_m, lambda: m_chain(lambda x: None, lambda x:2*x)(2))
None