# forbiddenfp
## Summary
Functional-Programming (FP) in a forbidden way:
You can turn arbitrary function into postfix notation in favor of function chaining.
And the library provides many useful patches for builtin/itertools functions.
## Install
Compatible with Python 3.7+
```shell
pip install forbiddenfp
```
## Examples
```python
# objects are already patched at import time
import forbiddenfp
"abc".print().len() # print out "abc", then return 3
"abc".then(lambda s: s * 2).filter(lambda s: s == "b").join() # "bb"
# A more complex one (examples/word_count.py)
("./lorem_ipsum.txt"
.with_open(lambda path, f: f.read().also(print(f"Reading {path}")))
.then(lambda s: s.split(" "))
.counter()
.print())
```
See more `./examples`.
## `_unpack`
For every higher-order-function chained, we provide an `_unpack` version as well.
e.g. `[(1, 2), (3, 4)].sum(lambda x: x[0] * x[1])`
can also be called as `[(1, 2), (3, 4)].sum_unpack(lambda x, y: x * y)`
## Why Functional Programming
Separate out control structs (which are functions provided by library) from business logic (which are lambda functions
supplied to fill the control structs).
So we can have a clearer scope, and separate concerns, when we want to change on either side of things.
- `if ...` and `if ... else ...` are modeled by Maybe/Either monads.
- `while ...` and `for ... in ...` are generator/iterators. Additionally, stop-early behavior is `takewhile` of the
sequence.
Philosophically, think more in `def transform(old_state) -> new_state`, rather than `state = modify(state)`.
## What About Auto-completion?
This library is almost an embedded Domain Specific Language (DSL) in Python.
It is understandable that users aren't familiar with what is available without auto-completion features in IDEs.
So we leverage the stub file to provide type hints for the builtin `object` type, which IntelliJ/PyCharm/VsCode all support.

In order to find where to stub, open your IDE and Python project/file, type `object` to get a class, CTRL/CMD + Click and use
"Find Definition" feature to get to the stub file of your IDE plugin.
Then copy/paste `src/forbiddenfp/__init__.py` under `class object` stub.
Note that for IntelliJ/Pycharm, once you CTRL + Click on `object`, you would need to click on the little icon below
to get to the *actual* stub file. Append content there.

## Warning
This library patches builtin `object` (and hence ALL classes),
with hacks around CPython API (provided by [forbiddenfruit](https://github.com/clarete/forbiddenfruit)),
so consider this NSFW (Not Safe For Work).
## Known Issues
`None` doesn't work well with chained keyword arguments.
```python
import forbiddenfp
None.apply(print) # works
None.apply(func=print) # doesn't work
```
Raw data
{
"_id": null,
"home_page": "https://github.com/yx-z/forbiddenfp",
"name": "forbiddenfp",
"maintainer": "",
"docs_url": null,
"requires_python": ">=3.7",
"maintainer_email": "",
"keywords": "",
"author": "David",
"author_email": "yx-z <yx-z@outlook.com>",
"download_url": "https://files.pythonhosted.org/packages/ab/4d/3f8de2487e37101a7275fa434b75777f4619026cea59363320429a536ed1/forbiddenfp-0.9.9.3.tar.gz",
"platform": null,
"description": "# forbiddenfp\n\n## Summary\n\nFunctional-Programming (FP) in a forbidden way:\n\nYou can turn arbitrary function into postfix notation in favor of function chaining.\n\nAnd the library provides many useful patches for builtin/itertools functions.\n\n## Install\n\nCompatible with Python 3.7+\n\n```shell\npip install forbiddenfp\n```\n\n## Examples\n\n```python\n# objects are already patched at import time\nimport forbiddenfp\n\n\"abc\".print().len() # print out \"abc\", then return 3\n\"abc\".then(lambda s: s * 2).filter(lambda s: s == \"b\").join() # \"bb\"\n\n# A more complex one (examples/word_count.py)\n(\"./lorem_ipsum.txt\"\n .with_open(lambda path, f: f.read().also(print(f\"Reading {path}\")))\n .then(lambda s: s.split(\" \"))\n .counter()\n .print())\n\n```\n\nSee more `./examples`.\n\n## `_unpack`\n\nFor every higher-order-function chained, we provide an `_unpack` version as well.\ne.g. `[(1, 2), (3, 4)].sum(lambda x: x[0] * x[1])`\ncan also be called as `[(1, 2), (3, 4)].sum_unpack(lambda x, y: x * y)`\n\n## Why Functional Programming\n\nSeparate out control structs (which are functions provided by library) from business logic (which are lambda functions\nsupplied to fill the control structs).\n\nSo we can have a clearer scope, and separate concerns, when we want to change on either side of things.\n\n- `if ...` and `if ... else ...` are modeled by Maybe/Either monads.\n- `while ...` and `for ... in ...` are generator/iterators. Additionally, stop-early behavior is `takewhile` of the\n sequence.\n\nPhilosophically, think more in `def transform(old_state) -> new_state`, rather than `state = modify(state)`.\n\n## What About Auto-completion?\n\nThis library is almost an embedded Domain Specific Language (DSL) in Python.\n\nIt is understandable that users aren't familiar with what is available without auto-completion features in IDEs.\n\nSo we leverage the stub file to provide type hints for the builtin `object` type, which IntelliJ/PyCharm/VsCode all support.\n\n\n\nIn order to find where to stub, open your IDE and Python project/file, type `object` to get a class, CTRL/CMD + Click and use\n\"Find Definition\" feature to get to the stub file of your IDE plugin.\n\nThen copy/paste `src/forbiddenfp/__init__.py` under `class object` stub.\n\nNote that for IntelliJ/Pycharm, once you CTRL + Click on `object`, you would need to click on the little icon below\nto get to the *actual* stub file. Append content there.\n\n\n\n## Warning\n\nThis library patches builtin `object` (and hence ALL classes),\nwith hacks around CPython API (provided by [forbiddenfruit](https://github.com/clarete/forbiddenfruit)),\n\nso consider this NSFW (Not Safe For Work).\n\n## Known Issues\n\n`None` doesn't work well with chained keyword arguments.\n\n```python\nimport forbiddenfp\n\nNone.apply(print) # works\nNone.apply(func=print) # doesn't work\n```\n",
"bugtrack_url": null,
"license": "",
"summary": "Forbidden Functional Programming in Python.",
"version": "0.9.9.3",
"project_urls": {
"Homepage": "https://github.com/yx-z/forbiddenfp",
"Issues": "https://github.com/yx-z/forbiddenfp/issues"
},
"split_keywords": [],
"urls": [
{
"comment_text": "",
"digests": {
"blake2b_256": "430c0ff73c0aa49de7ef38d01ef05f35c9439d4a0a756e0ccf2a440fc898277d",
"md5": "32712a20f8c7fffa9e4f8452182663b7",
"sha256": "db1a981a94066d107720834c71e6f28646083e36bd26a963a48a43152edf4334"
},
"downloads": -1,
"filename": "forbiddenfp-0.9.9.3-py3-none-any.whl",
"has_sig": false,
"md5_digest": "32712a20f8c7fffa9e4f8452182663b7",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": ">=3.7",
"size": 8031,
"upload_time": "2024-02-23T23:26:52",
"upload_time_iso_8601": "2024-02-23T23:26:52.067624Z",
"url": "https://files.pythonhosted.org/packages/43/0c/0ff73c0aa49de7ef38d01ef05f35c9439d4a0a756e0ccf2a440fc898277d/forbiddenfp-0.9.9.3-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": "",
"digests": {
"blake2b_256": "ab4d3f8de2487e37101a7275fa434b75777f4619026cea59363320429a536ed1",
"md5": "fb314ddb174160c8d77a0fec12f72042",
"sha256": "40e179f232cc32177aa0a3178e70a3cdb2a38f7ec8428b98cd4620b2c6542e5c"
},
"downloads": -1,
"filename": "forbiddenfp-0.9.9.3.tar.gz",
"has_sig": false,
"md5_digest": "fb314ddb174160c8d77a0fec12f72042",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">=3.7",
"size": 7877,
"upload_time": "2024-02-23T23:26:53",
"upload_time_iso_8601": "2024-02-23T23:26:53.844169Z",
"url": "https://files.pythonhosted.org/packages/ab/4d/3f8de2487e37101a7275fa434b75777f4619026cea59363320429a536ed1/forbiddenfp-0.9.9.3.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2024-02-23 23:26:53",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "yx-z",
"github_project": "forbiddenfp",
"travis_ci": false,
"coveralls": false,
"github_actions": false,
"requirements": [
{
"name": "forbiddenfruit",
"specs": []
},
{
"name": "typing_extensions",
"specs": []
}
],
"lcname": "forbiddenfp"
}