2012-04-04 9 views
4

Fragen:Fehlermonade in Python - habe ich es richtig gemacht?

  • Ist das eine Monade?
  • zeigt dies ein angemessenes Verständnis von Fehler Monade?
  • was fehlt mir?
  • was kann ich sonst noch mit diesem Code tun, um mehr Monaden zu machen?
  • Ich bin verwirrt über die Beziehung von Erfolg/nicht zu "Rückkehr"/"Ergebnis"/"Lift" (ich denke, das sind alle die gleichen Konzepte).
  • Wie können wir das Problem komplexer machen, so dass Monaden uns helfen, unsere Schmerzpunkte zu lösen? Monaden helfen hier, weil wir die if result != None Klempnerarbeit abstrahierten, welche anderen Arten von Klempnereien ich abstrahieren möchte, und wie helfen Monaden (oder "Monad-Kombinatoren") diesem Schmerz?

Ich bin ein wenig unterfordert.

# 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) 

Ausgang:

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

Sehr nette Frage. Ich denke, dass der Code in Ordnung ist, aber es könnte durch das Überladen des ">>" - Operators und das Verwenden von Lambdas stark aufgepeppt werden. Ein ganz anderer Ansatz ist der von [hier] (http://www.valuedlessons.com/2008/01/monads-in-python-wit-nice-syntax.html), dieser Typ benutzt Decorators und 'yield' um mache das fast richtig :) –

+0

Ich habe diesen Code leicht umstrukturiert, um ihn lesbarer zu machen. Hoffe, dass es dir nichts ausmacht (und wenn du es tust, bitte roll es zurück :) –

Antwort

2

Ist das eine Monade? Siehe monad laws:

Alle Instanzen der Monade Klasse gehorchen:

  1. "Left Identität": eine Rückkehr >> = f ≡ fa
  2. "Right Identität": m >> = Rück ≡ m
  3. "Assoziativität": (m >> = f) >> = g ≡ m >> = (\ x -> fx >> = g)

(return bedeutet Erfolg, >>= bedeutet binden)

  1. Linke Identität. In Ihrer Implementierung, könnte dies sein:

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

    wo x ist etwas Wert und f ist eine einstellige Funktion.

  2. Rechte Identität. Auch hier könnte dies sein:

    bind(m, success) == m 
    

    wo m einen monadischen Wert ist.

  3. Assoziativität. Dies könnte:

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

Alle diese als Unit-Tests geschrieben werden könnte, um schnell zu überprüfen, dass diese Eigenschaften für viele Eingangswerte halten.

Was fehlt?

  • jede Monade braucht eine andere Implementierung von success und bind. Wenn Sie diese in eine Schnittstelle einfügen, können Sie Code generisch über alle implementierten Monaden schreiben.
  • basierend auf the Haskell approach, möchten Sie vielleicht einige allgemeine Monad Kombinatoren wie >>, sequence und mapM zu implementieren. Diese machen Monaden sehr bequem zu benutzen.
+0

kannst du mein Problem so erweitern, dass Monad-Kombinierer mir helfen, es zu lösen? Ich denke, ich versuche zu verstehen, welche Art von Schmerzpunkten man haben könnte, die Monaden helfen zu lösen. –

Verwandte Themen