pamda

Pamda

PyPI version License: MIT

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 functions
    • thunkify arbitrary methods and functions
    • pipe 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

  1"""
  2# Pamda
  3[![PyPI version](https://badge.fury.io/py/pamda.svg)](https://badge.fury.io/py/pamda)
  4[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](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