комбинируя монады may и seq: вывод непонятен

Я пытаюсь составить seq-m и error-m, чтобы выполнить включение в список вещей, которые могут возвращать ошибки. Мой вывод имеет неожиданные типы, хотя в остальном он действительно кажется разумным. я взорвал свой код ниже, но вот рабочий смысл.

вот моя монадическая бизнес-логика

def get_loan(name):
    m_qualified_amounts = (
           bind(get_banks(name), lambda bank:
           bind(get_accounts(bank, name), lambda account:
           bind(get_balance(bank, account), lambda balance:
           bind(get_qualified_amount(balance), lambda qualified_amount:
                    unit(qualified_amount))))))
    return m_qualified_amounts

names = ["Irek", "John", "Alex", "Fred"]
for name, loans in zip(names, map(get_loan, names)):
    print "%s: %s" % (name, loans)

вывод

Irek: [None, 'Insufficient funds for loan, current balance is 35000', None, 'Insufficient funds for loan, current balance is 70000', None, 'Unable to get balance due to technical issue for Wells Fargo: 3']
John: [None, 'Insufficient funds for loan, current balance is 140000']
Alex: [[245000], None, [280000], None]
Fred: (None, 'No bank associated with name Fred')

я ожидаю увидеть списки кортежей - список является результатом понимания списка, и каждый элемент в окончательном списке должен быть значением в монаде ошибок ( значение , кортеж error). Это точно так же, как если бы с помощью seq_bindбыло удалено слишком много уровней вложенности.

вот мое определение монад, которое если и не верно, то очень близко, потому что обе монады работают изолированно, а не вместе.

def success(val): return val, None
def error(why): return None, why
def get_value(m_val): return m_val[0]
def get_error(m_val): return m_val[1]

# error monad
def error_unit(x): return success(x)
def error_bind(mval, mf):
    assert isinstance(mval, tuple)
    error = get_error(mval)
    if error: return mval
    else: return mf(get_value(mval))

def flatten(listOfLists):
    "Flatten one level of nesting"
    return [x for sublist in listOfLists for x in sublist]    

# sequence monad
def seq_unit(x): return [x]
def seq_bind(mval, mf):
    assert isinstance(mval, list)
    return flatten(map(mf, mval))

# combined monad !!
def unit(x): return error_unit(seq_unit(x))
def bind(m_error_val, mf):  
    return error_bind(m_error_val, lambda m_seq_val: seq_bind(m_seq_val, mf))

монадический API

def get_banks(name):
    if name == "Irek": return success(["Bank of America", "Wells Fargo"])
    elif name == "John": return success(["PNC Bank"])
    elif name == "Alex": return success(["TD Bank"])
    else: return error("No bank associated with name %s" % name)

def get_accounts(bank, name):
    if   name == "Irek" and bank == "Bank of America": return success([1, 2])
    elif name == "Irek" and bank == "Wells Fargo": return success([3])
    elif name == "John" and bank == "PNC Bank": return success([4])
    elif name == "John" and bank == "Wells Fargo": return success([5, 6])
    elif name == "Alex" and bank == "TD Bank": return success([7, 8])
    else: return error("No account associated with (%s, %s)" % (bank, name))

def get_balance(bank, account):
    if bank == "Wells Fargo":
        return error("Unable to get balance due to technical issue for %s: %s" % (bank, account))
    else:
        return success([account * 35000])  #right around 200,000 depending on acct number

def get_qualified_amount(balance):
    if balance > 200000:
        return success([balance])
    else:
        return error("Insufficient funds for loan, current balance is %s" % balance)

также ищет пути улучшения кода. пометил haskell и clojure, потому что это идиоматично для этих языков, сообщество Python не заинтересовано в этом.

10
задан Dustin Getz 8 April 2012 в 01:55
поделиться