2012-04-04 16 views
4

问题:Python中的monad错误 - 我做对了吗?

  • 这是一个monad吗?
  • 这是否证明了错误monad的合理理解?
  • 我错过了什么?
  • 我还可以用这个代码来做更多的单子吗?
  • 我对成功/失败与“返回”/“结果”/“提升”的关系感到困惑(我认为这些都是相同的概念)。
  • 我们如何才能使问题更加复杂,让monad帮助我们解决我们的痛点? monads在这里帮助我们,因为我们抽象出了管道,我想抽象什么其他类型的管道,以及单子(或单子组合器)如何帮助这种痛苦?

我有点不知所措。

# helpers for returning error codes 
def success(x): return (True, x) 
def fail(x): return (False, x) 

# bind knows how to unwrap the return value and pass it to 
# the next function 
def bind(mv, mf): 
    succeeded = mv[0] 
    value = mv[1] 

    if (succeeded): return mf(value) 
    else: return mv 

def lift(val): return success(val) 

def userid_from_name(person_name): 
    if person_name == "Irek": return success(1) 
    elif person_name == "John": return success(2) 
    elif person_name == "Alex": return success(3) 
    elif person_name == "Nick": return success(1) 
    else: return fail("No account associated with name '%s'" % person_name) 

def balance_from_userid(userid): 
    if userid == 1: return success(1000000) 
    elif userid == 2: return success(75000) 
    else: return fail("No balance associated with account #%s" % userid) 

def balance_qualifies_for_loan(balance): 
    if balance > 200000: return success(balance) 
    else: return fail("Insufficient funds for loan, current balance is %s" % balance) 

def name_qualifies_for_loan(person_name): 
    "note pattern of lift-bind-bind-bind, we can abstract further with macros" 
    mName = lift(person_name) 
    mUserid = bind(mName, userid_from_name) 
    mBalance = bind(mUserid, balance_from_userid) 
    mLoan = bind(mBalance, balance_qualifies_for_loan) 

    return mLoan 

for person_name in ["Irek", "John", "Alex", "Nick", "Fake"]: 
    qualified = name_qualifies_for_loan(person_name) 
    print "%s: %s" % (person_name, qualified) 

输出:

Irek: (True, 1000000) 
John: (False, 'Insufficient funds for loan, current balance is 75000') 
Alex: (False, 'No balance associated with account #3') 
Nick: (True, 1000000) 
Fake: (False, "No account associated with name 'Fake'") 
+1

非常好的问题。我认为代码是好的,因为它是,但它可以通过重载''>>操作和使用lambda表达式来五香了很多。一个完全不同的方法是从[这里]所述一个(http://www.valuedlessons.com/2008/01/monads-in-python-with-nice-syntax.html),那个人使用的装饰和'yield'到让这个几乎看起来是正确的:) – 2012-04-04 02:02:01

+0

我稍微调整了代码,使其更具可读性。希望你不介意(如果你这样做,请将它回滚:) – 2012-04-04 02:07:42

回答

2

这是一个单子?monad laws:单子类的

所有实例都应该遵守:

  1. “左身份”: 返回>> = F≡发
  2. “对身份”: 米>> =返回≡米
  3. “关联性”: (M >> = F)>> =克≡M >> =(\ X - > FX >> =克)

return表示成功,>>=意味着结合)

  1. 左身份。在您的实现,这可能是:

    bind(success(x), balance_qualifies_for_loan) == balance_qualifies_for_loan(x) 
    

    其中x一定的价值和f是一元函数。

  2. 正确的身份。同样,这可能是:

    bind(m, success) == m 
    

    其中m是一元的价值。

  3. Associativity。这可能是:

    bind(bind(m, userid_from_name), balance_from_userid)) == 
        bind(m, lambda x: bind(userid_from_name(x), balance_from_userid)) 
    

所有这些可以写成单元测试来快速检查这些属性保持多个输入值。

缺少什么?

  • 每个单子需要不同的执行successbind。把它们放到一个接口中可以让你编写所有实现的monads的通用代码。
  • 根据the Haskell approach,你可能想实现一些一般的单子组合程序,如>>sequencemapM。这些使monad非常方便使用。
+0

你能否扩展我的问题,使monad combinators帮助我解决它?我想我正在试图理解monad可以帮助解决的问题。 – 2012-04-04 02:17:14