2012-07-21 28 views
3

這個想法有多糟糕?類monad實現了with接口來放入和退出範圍,所以我可以編寫一個泛型函數庫,例如m_chain,它們指向函數unitbind,這些函數可以在運行時放入實現。 (不管這個代碼做了什麼,或者它是個好主意。)python:突變`globals`動態地把東西放在範圍內

其他想法我嘗試過所有圍繞包含單元/綁定作爲參數或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

似乎合法。我對一些答案會是什麼感興趣。我挖掘效果,讓您根據需要調整和調整功能的變化。如果有一個缺點,我沒有看到一個。我可能會小心地提供m_chains函數將要使用的函數的默認定義,或者如果它們沒有設置,則拋出一個有意義的異常,但否則我會看到一些像這樣的體面的應用程序。 – 2012-07-21 17:08:21

回答

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和似乎並不導致你失去任何靈活性。