Wrapper to allow algebraic manipulation and composition of functions. An abstract callable provides methods for chaining and combining functions, and defines an expression syntax for doing the same.
The aims of this package are purely academic; I do not recommend using this if you respect the people who must read your code.
from fungebra import Function
from external_library import other_func
@Function
def my_func():
...
other_func = Function(other_func)
In the following examples:
f
,g
,h
areFunction
wrapped callables.x
is an arbitrary argument.
(f + g)(x) == f.compose(g)(x) == f(g(x))
(f | g)(x) == f.pipe(g)(x) == g(f(x))
[1, 2, 3] | f == f([1, 2, 3])
[1, 2, 3] | f.collect == f(1, 2, 3)
(f << (1, 2, 3))(x) == f.partial(1, 2, 3)(x) == f(1, 2, 3, x)
(f << {"opt": "val"})(x) == f.partial({"opt": "val"})(x) == f(x, opt="val")
(f << Args(1, 2, opt="val"))(x) == f.partial(1, 2, opt="val")(x) == f(1, 2, x, opt="val")
(f >> (1, 2, 3))(x) == f.rpartial(1, 2, 3)(x) == f(x, 1, 2, 3)
(- f)(x) == f.map(x) == map(f, x)
(f - g)(x) == f.compose(g.map)(x) == map(g, f(x))
(f < g)(x) == f.filter(g)() == filter(g, f(x))
(f > g)(x) == f.reduce(g)(x) == reduce(g, f(x))
(- f > g)(x) == (f >= g)(x) == f.map.reduce(g)(x) == reduce(g, map(f, x))
(- f < g > h)(x) == f.map.filter(g).reduce(h)(x) == reduce(h, filter(g, map(f, x)))
(f <= g)(x) == f.map.filter(g)(x) == filter(g, map(f, x))
A number of compatible Function
callables are provided in fungebra.functions
. The operator
standard library is re-exported as Function
objects.
from fungebra import Function, operator as op
from fungebra.functions import less, fnot, itemgetter
greater_or_equal = less | fnot
@Function
def get_old_items_sort_by_name_desc(min_age: int):
"""Filter a known schema on old items, and sort by name descending."""
return itemgetter("hits").filter(
itemgetter("age") | greater_or_equal(min_age)
).pipe(
F(sorted) << {"key": itemgetter("name") | ord | op.neg}
).pipe(list)
get_old_items_sort_by_name_desc(2)(
{
"hits": [
{"age": 1, "name": "B"},
{"age": 2, "name": "A"},
{"age": 3, "name": "C"},
]
}
) == [
{"age": 3, "name": "C"},
{"age": 2, "name": "A"},
]
from fungebra import Function
from fungebra.functions import (
iffy, less, constantly, caller
)
@Function
def truncate_below(minimum: int) -> int:
"""Truncate arguments below a threshold."""
return caller(minimum).map([less, constantly]) | iffy.expand
truncate_below(0).lmap([-1, 2, 4]) == [0, 2, 4]
This package is currently tested for Python 3.6.
This project is not currently packaged and so must be installed manually.
Clone the project with the following command:
git clone https://github.com/jacksmith15/fungebra.git
Package requirements may be installed via pip install -r requirements.txt
. Use of a virtualenv is recommended.
- Clone the repository:
git clone [email protected]:jacksmith15/fungebra.git && cd fungebra
- Install the requirements:
pip install -r requirements.txt -r requirements-test.txt
- Run
pre-commit install
- Run the tests:
bash run_test.sh -c -a
This project uses the following QA tools:
- PyTest - for running unit tests.
- PyLint - for enforcing code style.
- MyPy - for static type checking.
- Travis CI - for continuous integration.
- Black - for uniform code formatting.
This project is distributed under the MIT license.