Functional Programming in Python
An attempt to improve the Functional programming paradigm supported by Python .
Since the start of my Computer Science course, I became quite affictionate to the concept of functional programming , one of the key concepts of the paradigm are monads which I tried to implement in Python.
Functional languages use monads to turn complicated sequences of functions into succinct pipelines that abstract away control flow, and side-effects.
Monads provide a way to structure a program.
They can be used (along with abstract data types) to allow actions (e.g. mutable variables) to be implemented safely.
Maybe Monads:
It can bind and flag if it contais a value.
Failure Monads:
It can bind, consecutively bind and abstract exceptions.
Lazy Monads:
It can bind, consecutively bind and late compute.
A parallelazible pool of Failure Monads:
If you want to use many Failure Monads that do not deppend on each other, why not parallelize it?
Using this class you can choose:
Import all classes from the Monads.py file
Create a Maybe Monad with a value inside:
Parameter
Type
Description
value
number
Not optional . The value of your monad.
Bind a Maybe monad with a function:
MaybeMonad(value).bind(function)
Parameter
Type
Description
value
number
Not optional . The value of your monad.
function
function
Not optional . A funtion to bind the value of the monad with.
Get the value from a Maybe monad:
MaybeMonad(value).bind(function).value
Parameter
Type
Description
value
number
Not optional . The value of your monad.
function
function
Not optional . A funtion to bind the value of the monad with.
def square(x):
return x**2
print(MaybeMonad(100).bind(square).value)
10000 #It applied the function to the value of the monad.
def square(x):
return x**2
print(MaybeMonad(100).bind(square).bind(square).value)
1000000 #It applied the function to the value of the monad twice
Create a Failure Monad with a value inside:
Parameter
Type
Description
value
number
Not optional . The value of your monad.
Bind a Failure Monad with a function:
FailureMonad(value).bind(function)
Parameter
Type
Description
value
number
Not optional . The value of your monad.
function
function
Not optional . A funtion to bind the value of the monad with.
Get the value from a Failure Monad:
FailureMonad(value).bind(function).value
Parameter
Type
Description
value
number
Not optional . The value of your monad.
function
function
Not optional . A funtion to bind the value of the monad with.
def square(x):
return x**2
print(FailureMonad(100).bind(square).value)
10000 #It applied the function to the value of the monad.
def square(x):
return x**2
print(FailureMonad(100).bind(square).bind(square).value)
1000000 #It applied the function to the value of the monad twice
Multiple argument functions support:
def div(x, y):
return x/y
print(FailureMonad(100).bind(div, 10).value)
10 #It applied the function to the value of the monad and the argument.
def div(x, y):
return x/y
print(FailureMonad(100).bind(div, 10).bind(div, 10).value)
1 #It applied the function to the value of the monad and the argument twice.
The key difference of Failure Monads is error handling:
def div(x, y):
return x/y
print(FailureMonad(100).bind(div, 0).value)
None #Instead of rising an Exception it returs None and updates the error status.
Get the error status of a failure monad
FailureMonad(value).bind(function).error_status
Parameter
Type
Description
value
number
Not optional . The value of your monad.
function
function
Not optional . A funtion to bind the value of the monad with.
def div(x, y):
return x/y
print(FailureMonad(100).bind(div, 0).error_status)
#It returns a dictionary containing every info of the exception/error.
Create a Lazy Monad with a value inside:
Parameter
Type
Description
value
number
Not optional . The value of your monad.
Bind a Lazy Monad with a function:
LazyMonad(value).bind(function)
Parameter
Type
Description
value
number
Not optional . The value of your monad.
function
function
Not optional . A funtion to bind the value of the monad with.
The key difference of Lazy monads is late computing, it only computes when asked.
FailureMonad(value).bind(function).compute()
Parameter
Type
Description
value
number
Not optional . The value of your monad.
function
function
Not optional . A funtion to bind the value of the monad with.
def square(x):
return x**2
print(LazyMonad(100).bind(square).compute())
10000 #It applied the function to the value of the monad.
def square(x):
return x**2
print(LazyMonad(100).bind(square).bind(square).compute())
1000000 #It applied the function to the value of the monad twice
Multiple argument functions support:
def div(x, y):
return x/y
print(LazyMonad(100).bind(div, 10).compute())
10 #It applied the function to the value of the monad and the argument.
def div(x, y):
return x/y
print(LazyMonad(100).bind(div, 10).bind(div, 10).compute())
1 #It applied the function to the value of the monad and the argument twice.
Since Lazy Monads do not handle errors like Failure Monads:
def div(x, y):
return x/y
print(LazyMonad(100).bind(div, 0))
# This does not rise an exception because it hasn't computed it yet
So if we compute it, then it rises an Exception because we are dividing by zero:
def div(x, y):
return x/y
print(LazyMonad(100).bind(div, 0).compute())
# Rises an Exception because we can't divide by zero.
Consecutive Binds Method: