Skip to content

Commit

Permalink
Linted with PEP8 --ignore='E731,W503'
Browse files Browse the repository at this point in the history
  • Loading branch information
justanr committed Mar 30, 2015
1 parent 7e1e977 commit 2a8dbe7
Show file tree
Hide file tree
Showing 13 changed files with 65 additions and 50 deletions.
2 changes: 1 addition & 1 deletion pynads/__init__.py
@@ -1,3 +1,3 @@
from .abc import *
from .concrete import *
from .funcs import *
from .funcs import *
6 changes: 4 additions & 2 deletions pynads/abc/applicative.py
Expand Up @@ -19,8 +19,9 @@ class ApplicativeMeta(ABCMeta):
def __rand__(self, other):
return self.unit(other)


class Applicative(with_metaclass(ApplicativeMeta, Functor)):
"""Applicative Functors are data types that can store potential
"""Applicative Functors are data types that can store potential
computations. Since Applicative Functors are also functors, they are also
mappable and must implement the `fmap` method.
Expand All @@ -29,7 +30,8 @@ class Applicative(with_metaclass(ApplicativeMeta, Functor)):
``apply`` is the way applicative interactive with each other. The initial
Applicative needs to be a function that will accept all following
Applicatives as arguments. It's possible to chain multiple calls to
apply together if the initial function accepts
apply together if the initial function returns a function
(or is curried).
>>> S_mul_two Something.unit(curry(lambda x, y: x*y))
>>> S_mul_two.apply(Something(4)).apply(Something(5))
Expand Down
6 changes: 2 additions & 4 deletions pynads/abc/container.py
Expand Up @@ -6,8 +6,8 @@ class Container(object):
should pass back to ``Container.__init__`` via super.
This class is the endpoint for any super() calls relating to
``__init__`` and ``_get_val`` unless multiple inheritance is used,
in which another class may also be called with these
``__init__`` and ``_get_val`` unless multiple inheritance is used,
in which another class may also be called with these
methods (including ``object``).
The value contained in this class is a *strong* reference by default.
Expand All @@ -20,8 +20,6 @@ class Container(object):
"""
__slots__ = ('_v', '__weakref__')

# accept *args, **kwargs for co-op inheritance with super
# note: Container is the endpoint for
def __init__(self, v=None, *a, **k):
self._v = v

Expand Down
14 changes: 7 additions & 7 deletions pynads/abc/functor.py
Expand Up @@ -2,17 +2,17 @@
from .container import Container
from ..utils import with_metaclass


class Functor(with_metaclass(ABCMeta, Container)):
"""Functors are data types that know how to be mapped over.
To implement the functor protocol, all the subclass needs to do is implement
fmap. fmap should return a new functor with the new data in it, preserving
all other data.
To implement the functor protocol, all the subclass needs to do is
implement fmap. fmap should return a new functor with the new data in it,
preserving all other data.
>>> class FMapDict(dict, Functor):
>>> def fmap(self, f):
>>> return FMapDict((k, f(v)) for k,v in self.items()))
>>> class FMapDict(dict, Functor):
>>> def fmap(self, f):
>>> return FMapDict((k, f(v)) for k,v in self.items()))
"""
__slots__ = ()

Expand Down
5 changes: 3 additions & 2 deletions pynads/abc/monad.py
@@ -1,12 +1,13 @@
from abc import abstractmethod
from .applicative import Applicative


class Monad(Applicative):
"""Base Monad class. Provides an abstract bind method
as well as two concrete methods: >> and <<=. These are
in addition to the abstract and concrete methods provided
by Applicative.
``bind`` should provide a value (or values) from the Monad
to a function that returns a Monad. However, there's no way
to reasonably enforce this in Python, so it's a contract.
Expand Down Expand Up @@ -56,7 +57,7 @@ def __rshift__(self, f):
def __ilshift__(self, f):
"""Helper operator. The same as using bind or >> but
as an assignment operator. The return value is *new* monad
not an altered one.
not an altered one.
>>> m = Right(4)
>>> m <<= lambda x: Right(x+2) if x < 1 else Left("greater than 1")
Expand Down
9 changes: 5 additions & 4 deletions pynads/concrete/either.py
Expand Up @@ -2,6 +2,7 @@
from ..abc import Monad
from ..utils import _propagate_self


class Either(Monad):
"""Enhanced version of Maybe. Represents a successful computation or
a failed computation with an error msg.
Expand All @@ -15,6 +16,7 @@ def __bool__(self):
def unit(v):
return Right(v)


class Left(Either):
"""Similar to Nothing in that it only returns itself when fmap, apply
or bind is called. However, Left also carries an error message instead
Expand All @@ -33,6 +35,7 @@ def __eq__(self, other):

fmap = apply = bind = _propagate_self


class Right(Either):
"""Represents a result of a computation. Similar to Just except it is
semantically a finished computation.
Expand All @@ -41,10 +44,10 @@ class Right(Either):

def __eq__(self, other):
return isinstance(other, Right) and other.v == self.v

def __repr__(self):
return "Right {!r}".format(self.v)

def fmap(self, f):
return Right(f(self.v))

Expand All @@ -53,5 +56,3 @@ def apply(self, applicative):

def bind(self, f):
return f(self.v)


27 changes: 17 additions & 10 deletions pynads/concrete/list.py
@@ -1,11 +1,12 @@
from collections.abc import Sequence, Mapping, Iterable
from itertools import chain
from collections.abc import Sequence, Iterable
from itertools import chain, repeat
from types import GeneratorType
from ..abc import Monad
from ..funcs import fmap
from ..utils import _iter_but_not_str_or_map


__all__ = ('List',)
__all__ = ('List', 'Generator')


class List(Monad, Sequence):
Expand Down Expand Up @@ -33,7 +34,7 @@ class List(Monad, Sequence):
>>> fs = [add_two, mul_two] & List
>>> fs * ([1,4,9] & List)
... List(2,8,18,3,6,11)
Despite the name, this Monad is closer to Python's ``tuple`` than ``list``
this is because Haskell's lists are immutable. List doesn't support
item assignment after creation.
Expand Down Expand Up @@ -81,25 +82,31 @@ def __repr__(self):

else:
body = ','.join([str(v) for v in self.v])

return main.format(body)

@classmethod
def unit(cls, v):
"""The most basic context for a List monad is a value in a tuple.
However, it's likely that strings and mappings shouldn't be splatted
into the delegated tuple.
If that's the desired behavior,
"""
if _iter_but_not_str_or_map(v):
return cls(*v)
return cls(v)

def fmap(self, f):
return List(*[f(v) for v in self.v])
return self.unit([f(v) for v in self.v])

def apply(self, applicative):
vals = [f(x) for f in self.v for x in applicative.v]
return List(*vals)
return self.unit(vals)

def bind(self, f):
return List(*chain.from_iterable(fmap(f, self)))
return self.unit(chain.from_iterable(fmap(f, self)))

# here be boring stuff...
def __hash__(self):
return hash(("List", self.v))
Expand Down Expand Up @@ -138,7 +145,7 @@ def __ge__(self, other):

def __add__(self, other):
if isinstance(other, List):
return List.unit(self.v + other.v)
return List.unit(self.v + other.v)
elif isinstance(other, tuple):
return List.unit(self.v + other)
raise TypeError("can only concatenate tuple or List with List")
Expand Down
5 changes: 3 additions & 2 deletions pynads/concrete/maybe.py
Expand Up @@ -9,7 +9,7 @@

class Maybe(Monad):
"""Represents a potential computation.
The actual constructor for Maybe doesn't return an instance of Maybe
but instead an instance of Just or the singleton Nothing.
Expand Down Expand Up @@ -57,9 +57,10 @@ def __eq__(self, other):
return self.v == other.v
return NotImplemented


class _Nothing(Maybe):
"""Singleton class representing a monadic failure in a computation.
fmap, apply and bind all return the singleton instance of Nothing
and short circuits all further bind operations.
"""
Expand Down
25 changes: 13 additions & 12 deletions pynads/concrete/reader.py
Expand Up @@ -2,6 +2,7 @@
from ..utils import iscallable, _get_name, _get_names
from ..funcs import const, compose


class Reader(Monad):
"""Monadic wrapper around a function. Compare to a Haskell implementation
(where R is short for Reader):
Expand All @@ -22,7 +23,7 @@ class Reader(Monad):
instance Monad (R e) where
return x = R $ \_ -> x
r >>= g = R $ \e -> runR (g (runR r e)) e
To understand the `>>=` definition, break it down as...
Expand All @@ -49,7 +50,7 @@ class Reader(Monad):
Each function in the bind chain needs to return an instance of Reader
when provided with an input:
>>> def inc(x):
>>> def inc(x):
... return x+1
>>> def adder(x):
... def add(y):
Expand Down Expand Up @@ -90,15 +91,15 @@ def __call__(self, env):
runR (R f) e = f e
It's a thin wrapper around a function that accepts an input of type `e`
and outputs a result of type `a`. `e` can be anything. The record syntax
(the first definition) simply defines a "selector function" to easily
extract the stored function, where as the second definition defines
the extractor externally.
and outputs a result of type `a`. `e` can be anything. The record
syntax (the first definition) simply defines a "selector function" to
easily extract the stored function, where as the second definition
defines the extractor externally.
Since the Reader monad is simply a wrapper around a function call,
the easiest way to emulate this in Python to define `__call__` that
accepts an input and runs the stored function with that input, returning
the result to the caller.
accepts an input and runs the stored function with that input,
returning the result to the caller.
"""
return self.v(env)

Expand Down Expand Up @@ -224,7 +225,7 @@ def apply(self, applicative):
# compare to:
# let (R f) = rf
# (R g) = rg
# in R $ \y -> (f y) (g y)
# in R $ \y -> (f y) (g y)
def applied(env, f=self, g=applicative):
"""First supply the environment to this Reader to get a function
back. And then call the returned function with the result of
Expand Down Expand Up @@ -270,13 +271,13 @@ def bind(self, g):
r >>= g = R $ \e -> let a = runR r e
s = g a
in runR s e
Keep in mind, this implementation of Reader utilizes Python's callable
object protocol instead of defining an exterior function (runR).
>>> inc = lambda x: x+1
>>> minc = lambda x: Reader(lambda y: x+y+1))
>>> s = R(inc) >> minc
>>> s = R(inc) >> minc
>>> s(1)
... 3
Expand Down Expand Up @@ -307,7 +308,7 @@ def bound(env, f=self, g=g):
return r(env)

names = _get_names(self.v, g)
bound.__doc__ = "Bind of {!s}".format(', '.join(names))
bound.__doc__ = "Bind of {!s}".format(', '.join(names))
bound.__name__ = '_x_'.join(names)

return self.__class__(bound)
Expand Down
1 change: 1 addition & 0 deletions pynads/concrete/writer.py
Expand Up @@ -3,6 +3,7 @@
from ..funcs import fmap
from .list import List


class Writer(Monad):
"""Stores a value as well as a log of events that have transpired
with the value.
Expand Down
2 changes: 1 addition & 1 deletion pynads/funcs.py
Expand Up @@ -5,6 +5,7 @@
__all__ = ('fmap', 'unit', 'multiapply', 'lift', 'multibind', 'const',
'identity', 'compose')


def fmap(f, functor):
"""Callable form of fmap."""
return functor.fmap(f)
Expand Down Expand Up @@ -108,7 +109,6 @@ def compose(*fs):
elif len(fs) == 1:
return fs[0]


def composed(*a, **k):
ret = fs[-1](*a, **k)
for f in fs[-2::-1]:
Expand Down
2 changes: 1 addition & 1 deletion pynads/utils.py
Expand Up @@ -33,7 +33,7 @@ def _single_value_iter(x):
def with_metaclass(meta, *bases):
"""Creates an anonymous object with a metaclass. Allows compatibility
between Python2 and Python3.
>>> class MyThing(with_metaclass(type)):
... pass
>>> MyThing.__mro__
Expand Down
11 changes: 7 additions & 4 deletions setup.py
@@ -1,7 +1,9 @@
import os, sys
import os
import sys
from setuptools import setup
from setuptools.command.test import test as TestCommand


class PyTest(TestCommand):
# Taken from py.test setuptools integration page
# http://pytest.org/latest/goodpractices.html
Expand All @@ -22,7 +24,9 @@ def run_tests(self):
errno = pytest.main(self.pytest_args)
sys.exit(errno)

tests_require = ['py', 'pytest']

tests_require = ['py', 'pytest']


if __name__ == "__main__":

Expand All @@ -37,5 +41,4 @@ def run_tests(self):
keywords="monad functor applicative",
test_suite='tests',
tests_require=tests_require,
cmdclass = {'test' : PyTest}
)
cmdclass={'test': PyTest})

0 comments on commit 2a8dbe7

Please sign in to comment.