Упрощение, возможно, Монады

Я пытаюсь понять, возможно, Monad, но в большинстве примеров, которые я видел, использовалась определенная языковая функция. Чтобы убедиться, что я получил это концептуально, я думал о написании родовой реализации. Ниже я придумал.

Может кто-нибудь сказать, правильно ли я понял это? Есть ли лучший способ обобщить его?

def f():
    return 2

def g():
    return 4

def h():
    return 7

def i():
    return None

def bind(val, func):
    if val is None:
        return None
    else:
        return(func())

unit = 0

>>> bind(bind(bind(unit,f),i),h) #Returns nothing
>>> bind(bind(bind(unit,f),g),h) #Returns a value
>>>7 

Что делать, если я хотел бы добавить значения из этих функций и прервать, если какой-либо из них был NULL; любое предложение?

Ответ 1

Вы очень близки, но подпись bind

m a -> (a -> m b) -> m b

Итак, он "разворачивается" m и передает указанное значение следующей функции. В настоящее время у вас

m a -> ( () -> m b) -> m b

Поскольку вы просто игнорируете привязку val, вы должны иметь

def bind(val, func):
    if val is None:
        return None
    else:
        return(func(val))

Это эквивалентно >>= в Haskell. То, что у вас было раньше, было >>, которое должно быть реализовано как

# "ignore" bind
def ibind(val, func):
    bind(val, lambda _ : func())

который просто счастливо выбрасывает значение bind, передает его.

Чтобы принять это дальше, вам нужно ввести класс

class Maybe():
    def __init__(v):
        self.val = v
        self.isNothing = False
Nothing = Maybe(None)
Nothing.isNothing = True

def bind(val, func):
    if val.isNothing:
        return Nothing
    else:
        return(func(val.val))