pamda
Pamda
Python wrapper for functional programming in object oriented structures.
Inspired heavily by Ramda.
Documentation for Pamda Functions
https://connor-makowski.github.io/pamda/pamda/pamda.html
Key Features
- Simplified functional programming for python
- Core Functions include:
curry
arbitrary methods and functionsthunkify
arbitrary methods and functionspipe
data iteratively through n functions
- List based path access and features for nested dictionaries
Setup
Make sure you have Python 3.9.x (or higher) installed on your system. You can download it here.
Installation
pip install pamda
Getting Started
Basic Usage
from pamda import pamda
data={'a':{'b':1, 'c':2}}
# Example: Select data given a path and a dictionary
pamda.path(['a','b'])(data) #=> 1
# See documentation for all core pamda functions at
# https://connor-makowski.github.io/pamda/pamda.html
Curry Usage
from pamda import pamda
# Define a function that you want to curry
def myFunction(a,b,c):
return [a,b,c]
# You can call pamda.curry as a function to curry your functions
curriedMyFn=pamda.curry(myFunction)
# Inputs can now be passed in an async fashion
# The function is evaluated when all inputs are added
x=curriedMyFn(1,2)
x(3) #=> [1,2,3]
x(4) #=> [1,2,4]
# Each set of inputs returns a callable function
# You can stack inputs on a single line for clean functional programming
curriedMyFn(1,2)(3) #=> [1,2,3]
For enforcing types, pamda relies on type_enforced but curried objects do not play nice with type_enforced
objects. To fix this, there is a special curry function, curryType
, that enables type_enforced annotations for your curried functions:
>>> from pamda import pamda
>>>
>>> # Pamda CurryTyped
>>> @pamda.curryTyped
... def add(a:int,b:int):
... return a+b
...
>>> add(1)(1)
2
>>> add(1)(1.5)
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
File "/home/conmak/development/personal/pamda/pamda/pamda_curry.py", line 43, in __call__
results = self.__fnExecute__(*new_args, **new_kwargs)
File "/home/conmak/development/personal/pamda/venv/lib/python3.10/site-packages/type_enforced/enforcer.py", line 90, in __call__
self.__check_type__(assigned_vars.get(key), value, key)
File "/home/conmak/development/personal/pamda/venv/lib/python3.10/site-packages/type_enforced/enforcer.py", line 112, in __check_type__
self.__exception__(
File "/home/conmak/development/personal/pamda/venv/lib/python3.10/site-packages/type_enforced/enforcer.py", line 34, in __exception__
raise TypeError(f"({self.__fn__.__qualname__}): {message}")
TypeError: (add): Type mismatch for typed variable `b`. Expected one of the following `[<class 'int'>]` but got `<class 'float'>` instead.
Thunkify Usage
from pamda import pamda
# Define a function that you want to thunkify
# thunkify can be called as a function or decorator
@pamda.thunkify
def myFunction(a,b,c):
return [a,b,c]
# The function is now curried and the evaluation is lazy
# This means the function is not evaluated until called
x=myFunction(1,2)
x(3) #=> <pamda.curry_obj object at 0x7fd514e4c820>
x(3)() #=> [1,2,3]
y=x(4)
y() #=> [1,2,4]
Thunkified functions can be executed asynchronously.
from pamda import pamda
import time
@pamda.thunkify
def test(name, wait):
print(f'{name} start')
time.sleep(wait)
print(f'{name} end')
return wait
async_test_a = pamda.asyncRun(test('a',2))
async_test_b = pamda.asyncRun(test('b',1))
async_test_a.asyncWait()
async_test_c = pamda.asyncRun(test('c',1))
The above code would output:
a start
b start
b end
a end
c start
c end
Pipe
from pamda import pamda
def square(x):
return x**2
def half(x):
return x/2
def negate(x):
return -x
# You can pipe data through multiple functions for clean functional programming
pamda.pipe([square, half, negate])(args=(6,),kwargs={}) #=> -18
Use pamda as a subclass
from pamda import pamda
class myClass(pamda):
def myFunction(self, a):
return self.inc(a)
mc=myClass()
mc.myFunction(2) #=> 3
@mc.curry
def addUp(a,b):
return a+b
addUp(1)(2) #=> 3
Pamda Utils
- Pamda also ships with a few helpful utilities
- Check out the documentation here:
1""" 2# Pamda 3[](https://badge.fury.io/py/pamda) 4[](https://opensource.org/licenses/MIT) 5 6Python wrapper for functional programming in object oriented structures. 7 8Inspired heavily by [Ramda](https://ramdajs.com/docs/). 9 10 11## Documentation for Pamda Functions 12https://connor-makowski.github.io/pamda/pamda/pamda.html 13 14## Key Features 15 16- Simplified functional programming for python 17- Core Functions include: 18 - `curry` arbitrary methods and functions 19 - `thunkify` arbitrary methods and functions 20 - `pipe` data iteratively through n functions 21- List based path access and features for nested dictionaries 22 23 24## Setup 25 26Make sure you have Python 3.9.x (or higher) installed on your system. You can download it [here](https://www.python.org/downloads/). 27 28### Installation 29 30``` 31pip install pamda 32``` 33 34## Getting Started 35 36### Basic Usage 37```py 38from pamda import pamda 39 40data={'a':{'b':1, 'c':2}} 41# Example: Select data given a path and a dictionary 42pamda.path(['a','b'])(data) #=> 1 43 44# See documentation for all core pamda functions at 45# https://connor-makowski.github.io/pamda/pamda.html 46``` 47 48### Curry Usage 49```py 50from pamda import pamda 51 52# Define a function that you want to curry 53def myFunction(a,b,c): 54 return [a,b,c] 55 56# You can call pamda.curry as a function to curry your functions 57curriedMyFn=pamda.curry(myFunction) 58 59# Inputs can now be passed in an async fashion 60# The function is evaluated when all inputs are added 61x=curriedMyFn(1,2) 62x(3) #=> [1,2,3] 63x(4) #=> [1,2,4] 64 65# Each set of inputs returns a callable function 66# You can stack inputs on a single line for clean functional programming 67curriedMyFn(1,2)(3) #=> [1,2,3] 68``` 69 70For enforcing types, pamda relies on [type_enforced](https://github.com/connor-makowski/type_enforced) but curried objects do not play nice with `type_enforced` objects. To fix this, there is a special curry function, `curryType`, that enables type_enforced annotations for your curried functions: 71 72```py 73>>> from pamda import pamda 74>>> 75>>> # Pamda CurryTyped 76>>> @pamda.curryTyped 77... def add(a:int,b:int): 78... return a+b 79... 80>>> add(1)(1) 812 82>>> add(1)(1.5) 83Traceback (most recent call last): 84 File "<stdin>", line 1, in <module> 85 File "/home/conmak/development/personal/pamda/pamda/pamda_curry.py", line 43, in __call__ 86 results = self.__fnExecute__(*new_args, **new_kwargs) 87 File "/home/conmak/development/personal/pamda/venv/lib/python3.10/site-packages/type_enforced/enforcer.py", line 90, in __call__ 88 self.__check_type__(assigned_vars.get(key), value, key) 89 File "/home/conmak/development/personal/pamda/venv/lib/python3.10/site-packages/type_enforced/enforcer.py", line 112, in __check_type__ 90 self.__exception__( 91 File "/home/conmak/development/personal/pamda/venv/lib/python3.10/site-packages/type_enforced/enforcer.py", line 34, in __exception__ 92 raise TypeError(f"({self.__fn__.__qualname__}): {message}") 93TypeError: (add): Type mismatch for typed variable `b`. Expected one of the following `[<class 'int'>]` but got `<class 'float'>` instead. 94``` 95 96 97### Thunkify Usage 98```py 99from pamda import pamda 100 101# Define a function that you want to thunkify 102# thunkify can be called as a function or decorator 103@pamda.thunkify 104def myFunction(a,b,c): 105 return [a,b,c] 106 107# The function is now curried and the evaluation is lazy 108# This means the function is not evaluated until called 109x=myFunction(1,2) 110x(3) #=> <pamda.curry_obj object at 0x7fd514e4c820> 111x(3)() #=> [1,2,3] 112 113y=x(4) 114y() #=> [1,2,4] 115``` 116 117Thunkified functions can be executed asynchronously. 118 119```py 120from pamda import pamda 121import time 122 123@pamda.thunkify 124def test(name, wait): 125 print(f'{name} start') 126 time.sleep(wait) 127 print(f'{name} end') 128 return wait 129 130async_test_a = pamda.asyncRun(test('a',2)) 131async_test_b = pamda.asyncRun(test('b',1)) 132async_test_a.asyncWait() 133async_test_c = pamda.asyncRun(test('c',1)) 134``` 135 136The above code would output: 137``` 138a start 139b start 140b end 141a end 142c start 143c end 144``` 145 146### Pipe 147```py 148from pamda import pamda 149 150def square(x): 151 return x**2 152 153def half(x): 154 return x/2 155 156def negate(x): 157 return -x 158 159# You can pipe data through multiple functions for clean functional programming 160pamda.pipe([square, half, negate])(args=(6,),kwargs={}) #=> -18 161``` 162 163### Use pamda as a subclass 164```py 165from pamda import pamda 166 167class myClass(pamda): 168 def myFunction(self, a): 169 return self.inc(a) 170 171mc=myClass() 172mc.myFunction(2) #=> 3 173 174@mc.curry 175def addUp(a,b): 176 return a+b 177 178addUp(1)(2) #=> 3 179``` 180 181## Pamda Utils 182 183- Pamda also ships with a few helpful utilities 184- Check out the documentation here: 185 - https://connor-makowski.github.io/pamda/pamda_utils.html""" 186from .pamda import pamda