Хабр Курсы для всех
РЕКЛАМА
Практикум, Хекслет, SkyPro, авторские курсы — собрали всех и попросили скидки. Осталось выбрать!
class Infixable(object):
def __init__(self, arg):
if callable(arg):
self.fn = arg
else:
self.val = arg
def __repr__(self):
if hasattr(self,'val'):
return '<Inf=%s>'%repr(self.val)
else:
return "<Inf(%d)>"%self.fn.func_code.co_argcount
def __or__(self, other):
# self | other
if not isinstance(other,Infixable):
# self | noninf
other = Infixable(other)
logging.debug("%s + %s",repr(self),repr(other))
if hasattr(self,'val') and hasattr(other,'fn'):
# val | fn -> fn=curry
return Infixable(lambda x: other.fn(self.val,x))
elif hasattr(self,'fn') and hasattr(other,'val'):
# fn | val -> val=fn(val)
return Infixable(self.fn(other.val))
else:
raise ValueError("bogus operands in chain")
def __ror__(self,other):
# noninf | self
return Infixable(other) | self
some_obj.set_name("abc").inrease_age().update_items([1,2,3]).validate().save()Функция, которая принимает обычное значение и возвращает результат в контексте (монадное значение), называется монадной функцией
List(pos) +'>>='+ raw_jumps +'>>='+ if_validфункция raw_jumps используется совместно с оператором '>==' из монады List, значит она должна быть монадической. raw_jumps должна принимать обычное значение координат, и возвращать результат в контексте (т.е. List(result)). но если посмотреть код выше, то функция определена иначе: raw_jumps = lambda (x, y): [ ... ] т.е. принимая координаты, функция возвращает объект встроенного типа list, который к монаде List не имеет отношения. или имеет? в чем магия?class TightropeWalkerProblem(Maybe): ... ). допустимо-ли подобное для монад? похоже, что изменение монады, каскадом, заставит изменять и все монадические функции, которые с ней связаны — возможно, лишь для того, чтобы они стали возвращать монадические значения нового типа. скорее всего, это не оптимальное решение, а правильное от меня ускользает. show(
begin()
+'>>='+ to_left(2)
+'>>='+ to_right(5)
+'>>='+ to_left(-2) # канатоходец упадёт тут
)
#coding:utf-8
class Functor(object):
def fmap(self, func):
raise NotImplementedError()
class Applicative(Functor):
def applicate(self, monad_value):
raise NotImplementedError()
class Monad(Applicative):
def bind(self, monad_func):
raise NotImplementedError()
def then(self, monad_func):
raise NotImplementedError()
@property
def result(self):
raise NotImplementedError()
#------------------------------------------------------------------
class Maybe(Monad):
@classmethod
def just(cls, x):
return cls(just=x)
@classmethod
def nothing(cls, msg=''):
return cls(nothing=True, just=msg)
@classmethod
def _from_monad_value(cls, monad_value):
assert isinstance(monad_value, Maybe)
nothing, value = monad_value.result
if nothing:
return cls.nothing(value)
return cls.just(value)
def __init__(self, just=None, nothing=False):
self._just = just
self._nothing = nothing
def fmap(self, func):
if self._nothing:
return self.nothing(msg=self._just)
return self.just(func(self._just))
def applicate(self, monad_value):
if self._nothing:
return self.nothing(msg=self._just)
nothing, val = monad_value.result
if nothing:
return self.nothing(msg=val)
return self.just(self._just(val))
def bind(self, monad_func):
if self._nothing:
return self.nothing(msg=self._just)
return self._from_monad_value(
monad_func(self._just))
def then(self, monad_func):
return self._from_monad_value(monad_func())
@property
def result(self):
return (self._nothing, self._just)
just = lambda x: Maybe.just(x)
nothing = lambda msg='': Maybe.nothing(msg)
liftMaybe = lambda fn: lambda x: just(fn(x))
justLoggable = lambda x: Maybe.just((x, []))
def loggable(fn):
def inner(value):
value, log = value
log.append('%s\t%s' % (fn.__doc__, repr(value)))
new_nothing, value = fn(value).result
if new_nothing:
if value:
log.append(value)
return nothing('\n'.join(log))
return just((value, log))
return inner
#------------------------------------------------------------------
if __name__ == '__main__':
def _newPole( (l, r) ):
diff = l - r
if diff > 3:
return nothing(u'Слишком много птиц слева!')
elif diff < -3:
return nothing(u'Слишком много птиц справа!')
return just( (l, r) )
def seatLeft(x):
@loggable
def inner((l, r)):
u'''Налево'''
return _newPole( (l + x, r) )
return inner
def seatRight(x):
@loggable
def inner((l, r)):
u'''Направо'''
return _newPole( (l, r + x) )
return inner
banana = lambda x: nothing(u'Ой, корка!')
banana.__doc__ = u'''Корка под ноги'''
banana = loggable(banana)
nothing, val = reduce(
lambda m, v: m.bind(v), # свёртка посредством bind
[
seatLeft(2),
seatRight(4),
seatLeft(-1),
banana
],
justLoggable( (0, 0) ) # начальное значение
).result
if nothing:
print val
else:
print 'OK!'
Монады в Python поподробнее