Last active
December 29, 2015 01:49
-
-
Save bgnori/7595741 to your computer and use it in GitHub Desktop.
itertoolsとcollections, functoolsの勉強が必要. 無限リストの扱いの都合上、pythonのlistをそのまま使うことはできない.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/python | |
# -*- coding=utf8 -*- | |
""" | |
kana notation: usint | for bind of monad, flatMap in Scala. | |
see http://labs.timedia.co.jp/2011/05/monad-in-python.html | |
need monad law test | |
a. Associativity | |
(m flatMap f) flatMap g == m flatMap (f flatMap g) | |
(m | f ) | g = m | (f | g) | |
b. left unit | |
unit(x) flatMap f == f(x) | |
unit(x) | f = f(x) | |
c. right unit | |
m flatMap unit = m | |
m | unit == m | |
need wrapper for list, set | |
need wrapper for function. | |
i.e. | |
in Scala | |
m map f == m flatMap ( x => unit(f(x))) == m flatMap (f andThen unit) | |
in kana notation with andThen defined as function with closure | |
m.map(f) == m | andThen(f, unit) | |
compose/andThen in Scala | |
f = h compose g | |
f = h(g(x)) | |
f = h andThen g | |
f = g(h(x)) | |
""" | |
from itertools import * | |
import collections | |
class Monad: | |
def __init__(self, x): | |
self.value = x | |
def bind(self, f): | |
""" | |
f returns M[U] from T, Do I need inspect f? | |
flatMap in Scala | |
| in kana notation | |
Mustbe overridden""" | |
raise NotImplementedError | |
def __or__(self, a_to_m_b): | |
""" bind is | in kana notation """ | |
return self.bind(a_to_m_b) | |
def __repr__(self): | |
return "%s(%s)"%(self.__class__.__name__, self.value,) | |
class Maybe(Monad): | |
def bind(self, f): | |
if isinstance(self, Nothing): | |
return self | |
else: | |
return f(self.value) | |
class Just(Maybe): | |
""" | |
>>> import functools | |
>>> curry = functools.partial | |
>>> def flip(f): | |
... return lambda x, y: f(y, x) | |
... | |
>>> def safe_div(dividend, divisor): | |
... if divisor == 0: | |
... return Nothing | |
... else: | |
... return Just(dividend / divisor) | |
... | |
>>> safe_rdiv = flip(safe_div) | |
>>> Just(4) | curry(safe_rdiv, 2) | |
Just(2) | |
""" | |
class Nothing(Maybe): | |
""" | |
wannat use None, it is more natural as python | |
>>> import functools | |
>>> curry = functools.partial | |
>>> def flip(f): | |
... return lambda x, y: f(y, x) | |
... | |
>>> def safe_div(dividend, divisor): | |
... if divisor == 0: | |
... return Nothing(None) | |
... else: | |
... return Just(dividend / divisor) | |
... | |
>>> safe_rdiv = flip(safe_div) | |
>>> Just(4) | curry(safe_rdiv, 0) | |
Nothing | |
>>> Just(4) | curry(safe_rdiv, 0) | curry(safe_rdiv, 5) | |
Nothing | |
""" | |
def __repr__(self): | |
return "Nothing" | |
class Try(Monad): | |
#>>> Try(4) | curry(unsafe_rdiv, 0) | |
""" | |
>>> import functools | |
>>> curry = functools.partial | |
>>> def flip(f): | |
... return lambda x, y: f(y, x) | |
... | |
>>> def unsafe_div(dividend, divisor): | |
... return dividend / divisor | |
>>> unsafe_rdiv = flip(unsafe_div) | |
>>> Try("4/0").run() | |
Failue(integer division or modulo by zero) | |
>>> Try("4/2").run() | |
Success(2) | |
>>> Try(lambda : 4/2).run() | |
Success(2) | |
>>> Try(lambda : 4/0).run() | |
Failue(integer division or modulo by zero) | |
""" | |
def run(self): | |
""" word 'apply' is not vacant for us""" | |
try: | |
if isinstance(self.value, str): | |
return Success(eval(self.value)) | |
return Success(self.value()) | |
except Exception, ex: | |
return Failue(ex) | |
def bind(self, f): | |
if isinstance(self, Success): | |
return self.run() | |
else: | |
return self | |
class Success(Try): | |
pass | |
class Failue(Try): | |
pass | |
class MonadicList(Monad): | |
"""maybe to be parametric, want it be metaclass, | |
i.e. | |
monadicList = unitof(list) | |
monadicSet = unitof(set) | |
etc. | |
>>> import functools | |
>>> curry = functools.partial | |
>>> ml = MonadicList((1, 2, 3)) | |
>>> ml | |
MonadicList(1, 2, 3) | |
>>> ml | (lambda x : x +1) | |
MonadicList(2, 3, 4) | |
""" | |
def __init__(self, x): | |
if isinstance(x, collections.Iterable): | |
self.value = x | |
else: | |
self.value = (x, ) | |
def bind(self, f): | |
return MonadicList(f(x) for x in self.value) | |
def map(self, f): | |
return map(f, self.value) | |
def __repr__(self): | |
return "%s(%s)"%(self.__class__.__name__, | |
", ".join(map(str, islice(self.value, 3)))) | |
def andThen(f, g): | |
def foo(*args, **kw): | |
return g(f(*args, **kw)) | |
return foo | |
if __name__ == "__main__": | |
import doctest | |
doctest.testmod() | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment