
Product
Socket Now Supports pylock.toml Files
Socket now supports pylock.toml, enabling secure, reproducible Python builds with advanced scanning and full alignment with PEP 751's new standard.
A lightweight functional programming library with numpy, jax and torch support.
There are two ways that you can start using fp
.
This library is still under development,
but beta versions will updated as necessary on PyPI.
git clone https://github.com/opeltre/fp
cd fp && poetry install
pip install funprogram
The fp
library relies on python metaclasses to emulate a static python type system of Type
instances.
Its motivation is to provide a strict yet flexible interface
to a polymorphic type system, implementing most the
abstractions of a cartesian closed category.
Being familiar with category theory is not a prerequisite for using fp
.
The package and documentation are also intended as a user-friendy
and didactic tools for getting used with functional programming concepts.
Type polymorphism was a necessary feature for the
downstream message-passing library topos that I started developing
during my PhD.
Overcoming 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.
fp.cartesian
moduleThe 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.
from fp import *
@Hom((Int, Str), Str)
def foo(n, s):
return ("-" * n).join([s] * n)
In fp
, typed functions are instances of the "top" type Hom.Object
which takes care automatic currying, i.e. returning the partial application of
the decorated callable when invoked with too few arguments.
>>> foo
Int -> Str -> Str: foo
>>> foo(2)
Str -> Str: foo 2
>>> foo(2)("Hello World!")
Str: "Hello World!--Hello World! "
Typed functions (including curried ones) can be composed with the @
operator:
>>> bar = Hom(Int, Str)(lambda n: '|' * n)
>>> baz = Int.mul
>>> foo(4) @ bar @ baz
Int -> Str: foo 4 . λ . mul 3
>>> (foo(4) @ bar @ baz(3))(2)
Str: "||||||----||||||----||||||----||||||"
fp.instances
moduleAlgebraic subclasses of Type
are defined in fp.instances.algebra
,
allowing transparent subclassing of numeric builtin types. The lifting and propagation of algebraic methods defined there is also used by Str
and List.Object
, by being declared instances of the Monoid
type class.
>>> from fp import Int, Float, Str, List
>>> greet = Str.add("👋 Welcome")
>>> greet
Str -> Str: add 👋 Welcome
>>> greet("! " + foo(2)(bar(3)))
"👋 Welcome! |||--|||"
The List
functor creates types inheriting from List.Objecŧ
, a subclass of list with a map
method. The map
method of any functorial type, e.g.
List(Str)
, is actually an alias for the List.fmap
class method. Only the target needs to be explicited when called with an untyped function.
>>> phone = List(Int)("0632501202")
>>> phone.map(lambda n: 2 << n, tgt=Int)
List Int : [1, 64, 8, 4, 32, 1, 2, 4, 1, 4]
>>> List.fmap(bar)
List Int -> List Str: map λ
>>> List.fmap(bar)(phone)
List Str : ['', '||||||', '|||', '||', '|||||', '', '|', '||', '', '||']
Other features include a State
monad with which one might indeed write
fun programs 💻🐒!
# `State(Int, Str)` subclasses `Int -> (Int, Str)`
@State(Int, Str)
def barbaz(n):
"""Update an integer and return a string."""
q, r = divmod(n, 2)
if q == 0:
return q, "|" if r else "*"
return q, "|<" if r else "*<"
# The `State(Int)` monad binds `a -> State(Int, b)` functions
@Hom(Str, State(Int, Str))
def foobarbaz(acc):
"""Do `barbaz` while the accumulator says to continue."""
# run with io.VERBOSITY = 1 to see intermediate steps
io.log(acc, v=1)
if len(acc) and acc[-1] == "<":
# accumulate output
accbarbaz = barbaz.map(Str.add(acc[:-1]))
# bind foobarbaz
return accbarbaz >> foobarbaz
else:
# return accumulator
return State(Int).unit(acc)
>>> foobarbaz.run(257)
(Int, Str): (0, '|*******|')
>>> foobarbaz(260)
Str: '**|*****|'
Other monads have found plenty of applications in abstracting IO contexts, error handling, data streams and asynchronous threads.
See the docs or the source for an exhaustive list of the currently implemented types, functors, monads, etc.
fp.tensors
moduleFor 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
subject to change.
>>> from fp.tensors import Torch, Jax, Numpy
>>> from fp.tensors import backends
>>> backends
List Backend: [Numpy, Jax, Torch]
>>> x, y, z = (B.range(3) * (10 ** i) for i, B in enumerate(backends))
>>> x
Numpy: [0 1 2]
>>> y + x.jax()
Jax: [0 11 22]
>>> z + (x + y.numpy()).torch()
Torch: [0, 111, 222]
Typed tensors are created by supplying shape tuples to the Tens
functor.
With Linear
and Otimes
, typed tensors form a closed monoidal
subcategory of Type
.
>>> from fp.tensors import Tens, Linear
>>> E = Tens((2, 3))
>>> F = Tens((4,))
>>> v = E.range()
Tens 2x3 : [[0, 1, 2],
[[3, 4, 5]]
>>> f = Linear(E, F)(Tensor.randn(4, 6))
>>> f(v).shape
(4,)
See examples/arrays.py and the docs for more details.
If you use fp
and experience bugs or inconsistencies,
please report an issue on the
github page.
When debugging fp
code, setting the following should be useful:
fp.io.VERBOSITY = 3
FAQs
A functional programming framework for python.
We found that funprogram demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Product
Socket now supports pylock.toml, enabling secure, reproducible Python builds with advanced scanning and full alignment with PEP 751's new standard.
Security News
Research
Socket uncovered two npm packages that register hidden HTTP endpoints to delete all files on command.
Research
Security News
Malicious Ruby gems typosquat Fastlane plugins to steal Telegram bot tokens, messages, and files, exploiting demand after Vietnam’s Telegram ban.