{"id":20139890,"url":"https://github.com/opeltre/fp","last_synced_at":"2025-04-09T18:23:16.808Z","repository":{"id":40410205,"uuid":"419690520","full_name":"opeltre/fp","owner":"opeltre","description":"Functional programming in python","archived":false,"fork":false,"pushed_at":"2024-10-19T19:10:39.000Z","size":463,"stargazers_count":4,"open_issues_count":4,"forks_count":0,"subscribers_count":3,"default_branch":"master","last_synced_at":"2024-10-20T06:08:00.180Z","etag":null,"topics":["fp","functors","monad-transformers","monads","types"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/opeltre.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2021-10-21T11:12:24.000Z","updated_at":"2024-09-24T22:29:20.000Z","dependencies_parsed_at":"2024-04-28T15:32:42.941Z","dependency_job_id":"40657e28-b1ba-4a91-9a9f-f8f2fed593be","html_url":"https://github.com/opeltre/fp","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/opeltre%2Ffp","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/opeltre%2Ffp/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/opeltre%2Ffp/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/opeltre%2Ffp/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/opeltre","download_url":"https://codeload.github.com/opeltre/fp/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248085995,"owners_count":21045249,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["fp","functors","monad-transformers","monads","types"],"created_at":"2024-11-13T21:48:19.323Z","updated_at":"2025-04-09T18:23:16.790Z","avatar_url":"https://github.com/opeltre.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# fp\n\nA lightweight functional programming library with \n[numpy], [jax] and [torch] support. \n\n- 🗒️ [docs]\n- 📁 [repository]\n\n[docs]:https://funprogram.readthedocs.io/en/latest/\n[repository]:https://github.com/opeltre/fp\n[numpy]:https://numpy.org\n[jax]:https://jax.readthedocs.io/en/latest/\n[torch]:https://pytorch.org/docs\n\n## Installation \n\nThis library is still under development. \nYou can install the latest 0.9.2 beta release from PyPI or clone \nthe project and build `fp` with poetry. \n\n### Install from PyPI\n\n```\npip install funprogram\n```\n\n### Install with poetry\n\nYou can use [poetry](https://python-poetry.org/) to build wheels \nfrom a specific commit. To install the poetry environment and try \nusing `fp`, you can do:\n```bash\n$ git clone https://github.com/opeltre/fp\n$ cd fp \u0026\u0026 poetry lock \u0026\u0026 poetry install\n$ poetry run python -i examples/barbaz.py\n```\n\n## Overview\n\nThe `fp` library relies on python [metaclasses] to emulate a static python type system of `Type` instances. \n\nIts motivation is to provide a strict yet flexible interface \nto a polymorphic type system, implementing most the \nabstractions of a [cartesian closed] category. \nBeing familiar with category theory is not a prerequisite for using `fp`. \nThe package and documentation are also intended as a user-friendy \nand didactic tools for getting used with functional programming concepts. \n\n[cartesian closed]: https://en.wikipedia.org/wiki/Cartesian_closed_category\n\n[metaclasses]: https://www.python.org/dev/peps/pep-3115/ \n\nType polymorphism was a necessary feature for the \ndownstream message-passing library [topos] that I started developing \nduring my PhD. \nOvercoming the mysterious difficulties of metaclass construction was a hard enough task for this latter project to ever really reach a definitive state, but development might perhaps resume as stable versions of the `fp` package are released. \n\n[topos]: https://github.com/opeltre/topos \n\n### `fp.cartesian` module\n\nThe type `Hom(A, B)` declares typed functions or type _morphisms_, with input in `A` and output in `B`. Functions with multiple inputs can be declared by supplying a tuple of types `A = (A0, A1, ...)` as input.\n\n```py\nfrom fp import *\n\n@Hom((Int, Str), Str)\ndef foo(n, s):\n    return (\"-\" * n).join([s] * n)\n```\n\nIn `fp`, typed functions are instances of the \"top\" type `Hom.Object` which takes care automatic currying, i.e. returning the partial application of \nthe decorated callable when invoked with too few arguments. \n\n```py\n\u003e\u003e\u003e foo\nInt -\u003e Str -\u003e Str: foo\n\u003e\u003e\u003e foo(2)\nStr -\u003e Str: foo 2\n\u003e\u003e\u003e foo(2)(\"Hello World!\")\nStr: \"Hello World!--Hello World! \"\n```\n\nTyped functions (including curried ones) can be composed with the `@` operator:\n\n```py\n\u003e\u003e\u003e bar = Hom(Int, Str)(lambda n: '|' * n)\n\u003e\u003e\u003e baz = Int.mul\n\u003e\u003e\u003e foo(4) @ bar @ baz \nInt -\u003e Str: foo 4 . λ . mul 3\n\u003e\u003e\u003e (foo(4) @ bar @ baz(3))(2)\nStr: \"||||||----||||||----||||||----||||||\"\n```\n\n### `fp.instances` module\n\nAlgebraic subclasses  of `Type` are defined in `fp.instances.algebra`, \nallowing transparent subclassing of numeric builtin types. The lifting and propagation of algebraic methods defined there is also used by `Str` \nand `List.Object`, by being declared instances of the `Monoid` type class.\n\n```py\n\u003e\u003e\u003e from fp import Int, Float, Str, List\n\u003e\u003e\u003e greet = Str.add(\"👋 Welcome\")\n\u003e\u003e\u003e greet \nStr -\u003e Str: add 👋 Welcome\n\u003e\u003e\u003e greet(\"! \" + foo(2)(bar(3)))\n\"👋 Welcome! |||--|||\"\n```\n\nThe `List` functor creates parameterized types inheriting from `List.Object`, \na subclass of the builtin `list`, enriched with a `map` method. \nThe `map` method of a functorial type `List(A)` \nis an alias for the `List.fmap` class method, of signature:\n\n```py\n\u003e\u003e\u003e List.fmap\n(A -\u003e B) -\u003e List A -\u003e List B\n```\nThe target type `B` only needs to be explicited when `List(A).map` is called with\nan untyped function argument. \n\n```py\n\u003e\u003e\u003e phone = List(Int)(\"0632501202\")\n\u003e\u003e\u003e phone.map(lambda n: 2 \u003c\u003c n, tgt=Int)\nList Int : [1, 64, 8, 4, 32, 1, 2, 4, 1, 4]\n\u003e\u003e\u003e List.fmap(bar)\nList Int -\u003e List Str: map λ\n\u003e\u003e\u003e List.fmap(bar)(phone)\nList Str : ['', '||||||', '|||', '||', '|||||', '', '|', '||', '', '||']\n```\n\nOther features include a `State` monad with which one might indeed write \nfun programs 💻🐒!\n\n```py\n# `State(Int, Str)` subclasses `Int -\u003e (Int, Str)`\n\n@State(Int, Str)\ndef barbaz(n):\n    \"\"\"Update an integer and return a string.\"\"\"\n    q, r = divmod(n, 2)\n    if q == 0:\n        return q, \"|\" if r else \"*\"\n    return q, \"|:\" if r else \"*:\"\n\n# The `State(Int)` monad binds `a -\u003e State(Int, b)` functions\n\n@Hom(Str, State(Int, Str))\ndef foobarbaz(acc):\n    \"\"\"Do `barbaz` while the accumulator says to continue.\"\"\"\n    # run with io.VERBOSITY = 1 to see intermediate steps\n    io.log(acc, v=1)\n    if not len(acc) or acc[-1] != \":\":\n        # return accumulator \n    else:\n        # accumulate barbaz recursively\n        accbarbaz = barbaz.map(Str.add(acc[:-1]))\n        # bind foobarbaz\n        return accbarbaz \u003e\u003e foobarbaz\n    else: \n        # return accumulator\n        return State(Int).unit(acc)\n\n\u003e\u003e\u003e foobarbaz(\":\").run(257)\n(Int, Str): (0, '|*******|')\n\u003e\u003e\u003e foobarbaz(\":\")(260)\nStr: '**|*****|'\n```\nOther monads have found plenty of applications \nin abstracting IO contexts, error handling, data streams and asynchronous \nthreads.\n\nSee the [docs] or the [source][instances] for an exhaustive list of \nthe currently implemented types, functors, monads, etc. \n\n[instances]: https://github.com/opeltre/fp/blob/master/fp/instances/__init__.py\n\n### `fp.tensors` module\n\nFor now, the `Tensor` class is an alias of `Torch`, while Arrays from other backends can be explictly created with `Jax` and `Numpy`. This part of the API is\nsubject to change. \n\n```py\n\u003e\u003e\u003e from fp.tensors import Torch, Jax, Numpy\n\u003e\u003e\u003e from fp.tensors import backends\n\u003e\u003e\u003e backends\nList Backend: [Numpy, Jax, Torch]\n\u003e\u003e\u003e x, y, z = (B.range(3) * (10 ** i) for i, B in enumerate(backends))\n\u003e\u003e\u003e x\nNumpy: [0 1 2]\n\u003e\u003e\u003e y + x.jax() \nJax: [0 11  22]\n\u003e\u003e\u003e z + (x + y.numpy()).torch()\nTorch: [0, 111, 222]\n```\n\nTyped tensors are created by supplying shape tuples to the  `Tens` functor. \nWith `Linear` and `Otimes`, typed tensors form a [closed monoidal] \nsubcategory of `Type`.\n\n[closed monoidal]: https://en.wikipedia.org/wiki/Closed_monoidal_category\n\n```py\n\u003e\u003e\u003e from fp.tensors import Tens, Linear\n\u003e\u003e\u003e E = Tens((2, 3))\n\u003e\u003e\u003e F = Tens((4,))\n\u003e\u003e\u003e v = E.range()\nTens 2x3 : [[0, 1, 2],\n           [[3, 4, 5]]\n\u003e\u003e\u003e f = Linear(E, F)(Tensor.randn(4, 6))\n\u003e\u003e\u003e f(v).shape\n(4,)\n```\n\nSee [examples/arrays.py](examples.arrays.py) and the [docs] for more details.\n\n## Contributing and troubleshooting\n\nIf you use `fp` and experience bugs or inconsistencies, \nplease report an issue on the \n[github](htts://github.com/opeltre/fp/issues) page.\nWhen debugging `fp` code, setting the following should be useful:\n\n```py\nfp.io.VERBOSITY = 3\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fopeltre%2Ffp","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fopeltre%2Ffp","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fopeltre%2Ffp/lists"}