coppertop - multiple-dispatch, partial functions and pipeline style for Python
Coppertop provides an alternative programming experience in Python via the following:
- multiple-dispatch
- partial functions
- piping syntax
- an embryonic core library of common functions
Installation
pip install coppertop-bones-libs for the dm core library and the @coppertop decorator.
pip install coppertop just for the @coppertop decorator.
At the moment needs to be git cloned and the setup.py manually run.
Multiple-dispatch
To use multiple-dispatch decorate functions with @coppertop and use different type annotations. Missing annotations are taken as fallback wildcards. Class inheritance is ignored when matching caller and function signatures.
from coppertop.pipe import *
@coppertop
def addOne(x:int) -> int:
return x + 1
@coppertop
def addOne(x:str) -> str:
return x + 'One'
@coppertop
def addOne(x): # fallback
if isinstance(x, list):
return x + [1]
else:
raise NotYetImplemented()
assert addOne(1) == 2
assert addOne('Three Two ') == 'Three Two One'
assert addOne([0]) == [0, 1]
Partial (application of) functions
syntax: f(_, a) -> f(_)
where _ is used as a sentinel place-holder for arguments yet to be confirmed (TBC)
We create partials of @coppertop decorated functions when we use _ indicating deferred arguments. For example:
from coppertop.pipe import *
@coppertop
def appendStr(x, y):
assert isinstance(x, str) and isinstance(y, str)
return x + y
appendWorld = appendStr(_, " world!") # first argument is deferred
assert appendWorld("hello") == "hello world!"
Piping syntax
The @coppertop function decorator also extends functions with the >> operator
and so allows code to be written in a more essay style format - i.e. left-to-right and
top-to-bottom. The idea is to make it easier to express program syntax (aka sequence).
unary style - takes 1 piped argument and 0+ called arguments
syntax: A >> f(args) -> f(args)(A)
from coppertop.pipe import *
@coppertop(style=unary)
def addOne(x):
return x + 1
1 >> addOne
"hello" >> appendStr(_," ") >> appendStr(_, "world!")
1 >> partial(lambda x: x +1)
binary style - takes 2 piped arguments and 0+ called arguments
syntax: A >> f(args) >> B -> f(args)(A, B)
from bones.core.errors import NotYetImplemented
from dm.core import collect, inject
@coppertop(style=binary)
def add(x, y):
return x + y
@coppertop(style=binary)
def op(x, action, y):
if action == "+":
return x + y
else:
raise NotYetImplemented()
1 >> add >> 1
1 >> op(_,"+",_) >> 1
[1,2] >> collect >> (lambda x: x + 1)
[1,2,3] >> inject(_,0,_) >> (lambda x,y: x + y)
ternary style - takes 3 piped arguments and 0+ called arguments
syntax: A >> f(args) >> B >> C -> f(args)(A, B, C)
from dm.core import both
from dm.testing immport check, equals
actual = [1,2] >> both >> (lambda x, y: x + y) >> [3,4]
assert (1 >> equal >> 1) == True
actual >> check >> equal >> [4, 6]
Examples
Bag of M&Ms problem
In Why coppertop - MM problem from Think Bayes.ipynb we implement a coppertop solution to the problem and silently introduce intersection types.
Cluedo notepad
See algos.py, where we track a game of Cluedo and infer who did it. See ex_games.py and cluedo-pad.ipynb for example game input and notepad output.
a whimsical exercise for the ambitious
(both, collect, inject, addOne, appendStr, check, equals are all illustrated above)
from dm.core import to
[1,2] >> both >> (lambda x, y: x + y) >> [3,4]
>> collect >> (lambda x: x * 2)
>> inject(_,1,_) >> (lambda x,y: x * y)
>> addOne >> addOne >> addOne
>> to >> str >> appendStr(_," red balloons go by")
>> check >> equal >> ???
Other
Thanks
Inspired by
- Magrittr - a piping library for R
- Arthur Whitney's ideas especially kdb/q and C style e.g. a tiny k interpreter for educational purposes
- Smalltalk - especially the ideas of Alan Kay & Rebecca Wirfs-Brock and the VisualWorks and Cuis implementations
- Alexander A. Stepanov's ideas on templating and generics
Built using
Metadata
Release files for coppertop-bones 2025.6.8
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| coppertop_bones-2025.6.8.tar.gz | 68.8 kB | Without provenance | Details for coppertop_bones-2025.6.8.tar.gz |
Release files / coppertop_bones-2025.6.8.tar.gz
| Download URL | coppertop_bones-2025.6.8.tar.gz |
|---|---|
| Size | 68.8 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
5d882e0f89a2761b8328c79a3560cd47f4e6a90d391ece65f7ee7893c34b6865
|
|
BLAKE2b-256 checksum How to use checksums |
b883bb8c65c7fc42caa45110e6f1daa614ba6126cdefedd41a20483f0dbfd8de
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.1.0 CPython/3.11.0
|
Security for coppertop-bones 2025.6.8
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.