3

这是多么可怕的想法?类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
4

1 回答 1

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

实际上,显式传递函数似乎更符合 Python 风格,并且似乎不会导致您失去任何灵活性。

于 2012-07-21T18:39:47.630 回答