3

これはどれほどひどい考えですか?クラスはスコープ内外に物事を置くmonadためのインターフェースを実装しているので、関数をwith参照し、実行時に実装を入れることができる m_chain のような汎用関数のライブラリを書くことができます。(このコードが何をするか、それが良いアイデアかどうかは問題ではありません。)unitbind

私が試した他のアイデアはすべて、引数または kwarg として unit/bind を含む構造体を渡すこと、または m_chain をクラスに入れ、それを self.unit および self.bind に関して実装し、派生クラスにそれらを提供させることを中心に展開しました。しかし、コードと構文に複雑さが加わり、ユニット/バインドが 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

実際に関数を明示的に渡すと、より Pythonic に見え、柔軟性が失われることはないようです。

于 2012-07-21T18:39:47.630 に答える