Metadata-Version: 1.1
Name: PyMonad
Version: 1.2
Summary: Collection of classes for programming with functors, applicative functors and monads.
Home-page: http://pypi.python.org/pypi/PyMonad
Author: Jason DeLaat
Author-email: jason.develops@gmail.com
License: Copyright (c) 2014, Jason DeLaat
All rights reserved.

Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:

1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.

2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.

3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

Description: =======
        PyMonad
        =======
        
        PyMonad is a small library 
        implementing monads and related data abstractions
        -- functors, applicative functors, and monoids --
        for use in implementing functional style programs.
        For those familiar with monads in Haskell,
        PyMonad aims to implement many of the features you're used to
        so you can use monads in python quickly and easily.
        For those who have never used monads but are interested,
        PyMonad is an easy way to learn about them in, perhaps, 
        a slightly more forgiving environment
        without needing to learn Haskell.
        
        Features
        ========
        
        * Easily define curried functions with the ``@curry`` decorator.
        * Straight-forward partial application: just pass a curried function the number of arguments you want.
        * Composition of curried functions using ``*``.
        * Functor, Applicative Functor, and Monad operators: ``*``, ``&``, and ``>>``
        * Five basic monad types
        * Monoids
        
        1. Maybe - for when a calculation might fail
        2. Either - Similar to Maybe but with additional error reporting
        3. List - For non-deterministic calculations
        4. Reader - For sequencing calculations which all access the same data.
        5. Writer - For keeping logs of program execution.
        
        Getting Started
        ===============
        
        Installation
        ------------
        
        Using pip::
        
        	pip install PyMonad
        
        Or download the package and run::
        
        	python setup.py install
        
        from the project directory.
        	
        Imports
        -------
        
        Import the entire package::
        	
        	from pymonad import *
        
        Or just a single monad type::
        
        	from pymonad.Maybe import *
        
        If you're not importing everything
        but want to use curried functions::
        
        	from pymonad.Reader import curry
        
        Curried Functions and Partial Application
        -----------------------------------------
        
        To define a curried function
        use the ``@curry`` decorator::
        
        	@curry
        	def add(x, y):
        		return x + y
        
        	@curry
        	def func(x, y, z):
        		# Do something with x, y and z.
        		...
        
        The above fuctions can be partially applied 
        by passing them less than their full set of arguments::
        
        	add(7, 8)			# Calling 'add' normally returns 15 as expected.
        	add7 = add(7)		# Partial application: 'add7' is a function taking one argument.
        	add7(8)				# Applying the final argument retruns 15...
        	add7(400)			# ... or 407, or whatever.
        
        	# 'func' can be applied in any of the following ways.
        	func(1, 2, 3)		# Call func normally.
        	func(1, 2)(3)		# Partially applying two, then applying the last argument.
        	func(1)(2, 3)		# Partially applying one, then applying the last two arguments.
        	func(1)(2)(3)		# Partially applying one, partially applying again, then applying the last argument.
        
        Function Composition
        --------------------
        
        Curried functions can be composed with the ``*`` operator.
        Functions are applied from right to left::
        	
        	# Returns the first element of a list.
        	@curry
        	def head(aList): 
        		return aList[0]
        
        	# Returns everything except the first element of the list.
        	@curry 
        	def tail(aList): 
        		return aList[1:]
        
        	second = head * tail		# 'tail' will be applied first, then its result passed to 'head'
        	second([1, 2, 3, 4])		# returns 2
        
        You can also compose partially applied functions::
        
        	@curry
        	def add(x, y): 
        		return x + y
        
        	@curry
        	def mul(x, y): 
        		return x * y
        
        	comp = add(7) * mul(2)		# 'mul(2)' is evaluated first, and it's result passed to 'add(7)'
        	comp(4)						# returns 15
        
        	# Composition order matters!
        	comp = mul(2) * add(7)
        	comp(4)						# returns 22
        
        Functors, Applicative Functors, and Monads
        ------------------------------------------
        
        All Monads are also Applicative Functors,
        and all Applicative Functors are also Functors,
        though the same is not necessarily true in reverse.
        All the types included with PyMonad
        are defined as all three
        but you can define new types however you want.
        
        All of these types ultimately derive from ``Container``
        which simply holds a value and provides some basic value equality checking.
        The method ``getValue()`` will allow you to "extract" the value 
        of monadic computations if/when necessary.
        
        Functors
        --------
        
        All functors define the ``fmap`` method
        which can be invoked via the fmap operator ``*``.
        ``fmap`` takes functions which operate on simple types
        -- integers, strings, etc. --
        and allows them to operate of functor types::
        	
        	from pymonad.Maybe import *
        	from pymonad.List import *
        
        	# 'neg' knows nothing about functor types...
        	def neg(x):
        		return -x
        
        	# ... but that doesn't stop us from using it anyway.
        	neg * Just(9)				# returns Just(-9)
        	neg * Nothing				# returns Nothing
        	neg * List(1, 2, 3, 4)		# returns List(-1, -2, -3, -4)
        
        Notice that the function is on the left
        and the functor type is on the right.
        If you think of ``*`` as a sort of fancy opening paren,
        then normal calls and ``fmap`` calls have basically the same structure::
        
        	------------------------------------------------------------------
        					function		open		argument		close
        	Normal call		  neg			 (			   9			  )
        	fmap call	 	  neg			 *			 Just(9)
        	------------------------------------------------------------------
        
        
        Notice that ``*`` is also the function composition operator.
        In fact,
        curried functions are instances of the ``Reader`` monad,
        and ``fmap`` -ing a function over another function
        is the same thing as function composition.
        
        Applicative Functors
        --------------------
        
        Functors allow you to use normal functions of a single argument
        -- like ``neg`` above --
        with functor types.
        Applicative Functors extend that capability
        -- via ``amap`` and its operator ``&`` --
        allowing you to use normal functions of multiple arguments
        with functor types::
        
        	# 'add' operates on simple types, not functors or applicatives...
        	def add(x, y):
        		return x + y
        
        	# ... but we're going to use it on those types anyway.
        	# Note that we're still using '*' but now in conjunction with '&'
        	add * Just(7) & Just(8)					# returns Just(15)
        	add * Nothing & Just(8)					# returns Nothing
        	add * Just(7) & Nothing					# returns Nothing
        	add * List(1, 2, 3) & List(4, 5, 6)		# returns List(5, 6, 7, 6, 7, 8, 7, 8, 9)
        
        If ``*`` is a fancy paren,
        ``&`` is the fancy comma
        used to separate arguments.
        
        Monads
        ------
        
        Monads allow you to sequence a series of calculations
        within than monad
        using the ``bind`` operator ``>>``.
        
        The first argument to ``>>`` is a monad type.
        The second argument is a function
        which takes a single,
        non-monad argument
        and returns an instance of the same monad::
        
        	from pymonad.List import *
        	from pymonad.Reader import curry
        
        	# Takes a simple number type and returns a 'List' containing that value and it's negative.
        	def positive_and_negative(x):
        		return List(x, -x)
        
        	# You can call 'positive_and_negative' normally.
        	positive_and_negative(9)		# returns List(9, -9)
        
        	# Or you can create a List...
        	x = List(9)
        
        	# ... and then use '>>' to apply positive_and_negative'
        	x >> positive_and_negative		# also returns List(9, -9)
        
        	# But 'x' could also have more than one value...
        	x = List(1, 2)
        	x >> positive_and_negative		# returns List(1, -1, 2, -2)
        
        	# And of course you can sequence partially applied functions.
        	@curry
        	def add_and_sub(x, y):
        		return List(y + x, y - x)
        
        	List(2) >> positive_and_negative >> add_and_sub(3)		# creates List(2)
        															# applies positive_and_negative: List(2, -2)
        															# then add_and_sub(3): List(5, -1, 1, -5)
        															# final result: List(5, -1, 1, -5)
        
        Variable assignment in monadic code
        -----------------------------------
        
        The second argument to ``>>`` is a function 
        which takes a single, non-monad argument.
        Because of that, 
        you can use ``lambda`` to assign values to a variable
        withing monadic code,
        like this::
        	
        	from pymonad.Maybe import *
        
        	Just(9) >> (lambda x: 				# Here, 'x' takes the value '9'
        	Just(8) >> (lambda y:				# And 'y' takes the value '8'
        	Just(x + y)))						# The final returned value is 'Just(9 + 8)', or 'Just(17)'
        
        You can also simply ignore values if you wish::
        
        	Just(9) >> Just(8)					# The '9' is thrown away and the result of this computation is 'Just(8)'
        
        Implementing Monads
        -------------------
        
        Implementing other functors, applicatives, or monads is fairly straight-forward.
        There are three classes, 
        serving as interfaces::
        
        	Monad --> Applicative --> Functor
        
        To implement a new functor,
        create a new class which derives from ``Functor``
        and override the ``fmap`` method.
        
        To implement a new applicative functor,
        create a new class which derives from ``Applicative``
        and override the ``amap`` and ``fmap`` methods.
        
        To implement a new monad,
        create a new class which derives from ``Monad``
        and override at least the ``bind`` method, 
        and preferably the ``amap`` and ``fmap`` methods as well.
        
        The operators, ``*``, ``&``, and ``>>``
        are pre-defined to call the above methods
        so you shouldn't need to touch them directly.
        
        unit (aka return)
        -----------------
        
        The previous version of pymonad
        didn't include the method ``unit``
        (called ``return`` in Haskell).
        ``unit`` takes a bare value,
        such as ``8``,
        and places it in a default context for that monad.
        Haskell allows polymorphism on return types 
        as well as supporting type inference,
        so you (mostly) don't have to tell ``return`` what types to expect,
        it just figures it out.
        We can't do that in Python,
        so you *always* need to tell ``unit`` what type you're expecting.
        
        The ``unit`` method is implemented as a class method
        in Functor.py, so it can be used with any functor, applicative or monad.
        There is also a ``unit`` *function* which expects a functor type
        (though you can also give it an instance) 
        and a value
        and invokes the corresponding ``unit`` method.
        It is provided to give a more "functional look" to code,
        but use whichever method you prefer.
        With the Maybe monad for example:
        
        1. Maybe.unit(8)		# returns Just(8)
        2. unit(Maybe, 8)		# also returns Just(8)
        
        In either case all functors (and applicatives and monads) should implement the ``unit`` class method.
        
        Monoids
        =======
        
        Monoids are a data type 
        which consists of some operation for combining values of that type,
        and an identity value for that operation.
        The operation is called ``mplus`` 
        and the identity value is callled ``mzero``.
        Despite the names,
        they are not necessarily addition and zero.
        They *can* be addition and zero though,
        numbers are sort of the typical monoid.
        
        In the case of numbers,
        zero is the identity element and addition is the operation.
        Monoids adhere to the following laws:
        
        1. Left and right identity: x + 0 = 0 + x = x	 
        2. Associativity: (x + y) + z = x + (y + z) = x + y + z 	
        
        Stings are also monoids with the identity element ``mzero`` equal to the empty string,
        and the operation ``mplus`` concatenation.
        
        Creating New Monoids
        --------------------
        
        To create a new monoids type
        create a class deriving from ``Monoid``
        and override the ``mzero`` static method
        which takes no arguments and should return an instance of the class
        containing the identity value for the monoid.
        Also override the ``mplus`` method.
        For instance,
        numbers can be a monoid in two ways,
        one way with zero and addition as discussed above
        and the other way with one and multiplication.
        We could implement that like this::
        
        	class ProductMonoid(Monoid):
        		@staticmethod
        		def mzero():
        			return ProductMonoid(1)
        
        		def mplus(self, other):
        			return ProductMonoid(self.getValue() * other.getValue())
        
        The ``+`` operator (aka __add__()) is defined to call ``mplus`` on monoid instances,
        so you can simply "add" monoid values together rather than having to call ``mplus`` directly.
        
        "Natural" Monoids
        -----------------
        
        Similar to ``unit`` for monads,
        there is an ``mzero`` function
        which expects a type and can be used instead of the ``mzero`` method.
        Unlike ``unit`` however,
        the ``mzero`` function serves another purpose.
        Numbers, strings and lists can all be used as monoids
        and all already have an appropriate definition for ``+``.
        What they don't have is an ``mzero`` method.
        To allow numbers, strings and lists to be used as monoids
        without any extra work,
        the ``mzero`` *function* will return the appropriate value for these types
        and will attempt to call the ``mzero`` method on anything else.
        For instance::
        
        	mzero(int)					# returns 0, also works with float
        	mzero(str)					# returns ""
        	mzero(list)					# returns []
        	mzero(ProductMonoid)		# return ProductMonoid(1)
        	# etc...
        
        If you write code involving monoids,
        and you're not sure what type of monoid you might be handed,
        you should use the ``mzero`` *function* 
        and *not* the ``mzero`` method.
        
        Monoids and the Writer Monad
        ============================
        
        The Writer monad performs calculations 
        and keeps a log.
        The log can be any monoid type
        -- strings being a typical example.
        
        The ``Writer`` class doesn't have a default log type,
        so to use Writer you need to inherit from it.
        It is extremely simple as the only thing you need to do is define the log type.
        For instance::
        
        	class StringWriter(Writer):
        		logType = str
        
        That's it.
        Everything else is already defined by ``Writer``.
        ``StringWriter``, ``NumberWriter``, and ``ListWriter``
        are already defined in the ``Writer`` module for you to use.
        
        Calling ``unit`` with a ``Writer`` class
        packages whatever value you give it
        with the ``mzero`` of the log type::
        
        	unit(StringWriter, 8)		# Returns Writer(8, "")
        
        ``Writer`` constructors take two values,
        the first being the result of whatever calculation you've just performed,
        the second being the log message 
        -- or value, or whatever --
        to add to the log.
        
        ### Other Methods ###
        
        ``getValue()``: Returns the result and log as a two-tuple.
        
        ``getResult()``: Returns only the result.
        
        ``getLog()``: Returns only the log.
        
        A quick example::
        
        	@curry
        	def add(x, y):
        		return StringWriter(x + y, "Adding " + str(x) + " and " + str(y) + ". ")
        
        	x = unit(StringWriter, 8) >> add(4) >> add(5)
        	print(x.getResult()) 	# prints 17
        	print(x.getLog())		# prints "Adding 8 and 4. Adding 12 and 5. "
        
        In the definition of ``add`, 
        ``StringWriter`` could have also been just ``Writer``.
        It's really only necessary to use subclasses when using ``unit``,
        because ``unit`` checks for the ``logType`` variable.
        Otherwise simply giving plain old ``Writer`` a string
        -- or other monoid type argument --
        accomplishes the same thing.
        Both ``unit`` and ``bind`` (or ``>>``)
        convert ``*Writer`` types to plain ``Writer``
        but using ``StringWriter``
        -- or whatever --
        makes your intentions more clear.
        Changes
        =======
        
        V1.2, 2014-- -- Added Monoids and Writer Monad. Added 'unit' class method to existing monad types. Added 'unit' function. Updated README.txt for new features.
        V1.1, 2014-04-13 -- Fixed problems with List, Either and Maybe to make package compatible with Python 2
        V1.0, 2014-03-29 -- Initial Release
        
Platform: UNKNOWN
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: BSD License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 2.7
Classifier: Programming Language :: Python :: 3
Classifier: Topic :: Software Development
Classifier: Topic :: Software Development :: Libraries
Classifier: Topic :: Utilities
