monad
实现了with
接口以将事物放入和放出作用域,因此我可以编写一个通用函数库,如m_chain,它们引用函数unit
和bind
谁可以在运行时放入实现。 (所有这些代码的作用或者它是一个好主意并不重要。)
我试过的其他想法都围绕着传递一个包含unit / bind作为参数或kwarg的结构,或者将m_chain放在一个类中,用self.unit和self.bind来实现它,并让派生类提供它们。但它增加了代码和语法的复杂性,并将单元/绑定与monad在python中表达的方式联系起来。使用范围只是感觉好多了。
class monad:
"""Effectively, put the monad definition in lexical scope.
Can't modify the execution environment `globals()` directly, because
after globals().clear() you can't do anything.
"""
def __init__(self, monad):
self.monad = monad
self.oldglobals = {}
def __enter__(self):
for k in self.monad:
if k in globals(): self.oldglobals[k]=globals()[k]
globals()[k]=self.monad[k]
def __exit__(self, type, value, traceback):
"""careful to distinguish between None and undefined.
remove the values we added, then restore the old value only
if it ever existed"""
for k in self.monad: del globals()[k]
for k in self.oldglobals: globals()[k]=self.oldglobals[k]
def m_chain(*fns):
"""returns a function of one argument which performs the monadic
composition of fns"""
def m_chain_link(chain_expr, step):
return lambda v: bind(chain_expr(v), step)
return reduce(m_chain_link, fns, unit)
identity_m = {
'bind':lambda v,f:f(v),
'unit':lambda v:v
}
with monad(identity_m):
assert m_chain(lambda x:2*x, lambda x:2*x)(2) == 8
maybe_m = {
'bind':lambda v,f:f(v) if v else None,
'unit':lambda v:v
}
with monad(maybe_m):
assert m_chain(lambda x:2*x, lambda x:2*x)(2) == 8
assert m_chain(lambda x:None, lambda x:2*x)(2) == None
答案 0 :(得分:0)
我认为连续打击全球化绝对是一个糟糕的主意。依赖全局变量看起来就像你在这里模仿的功能风格的对立面。
为什么不将m_chain定义为:
def m_chain(bind, *fns):
"""returns a function of one argument which performs the monadic
composition of fns"""
def m_chain_link(chain_expr, step):
return lambda v: bind(chain_expr(v), step)
return reduce(m_chain_link, fns, unit)
然后:
identity_m = {
'bind':lambda v,f:f(v),
'unit':lambda v:v
}
with monad(identity_m):
assert m_chain(lambda x:2*x, lambda x:2*x)(2) == 8
变得简单:
assert m_chain(lambda v,f:f(v), lambda x:2*x, lambda x:2*x)(2) == 8
实际上明确地传递函数似乎更加pythonic并且似乎不会导致您失去任何灵活性。