Skip to main content

Piping and multi-dispatch for python

Project description

coppertop - piping and multi-dispatch for python

Coppertop provides a bones-style aggregation manipulation experience in python via the following:

  • partial (application of) functions
  • piping syntax
  • multiple-dispatch
  • type system with primitives, intersections, unions, products, exponentials, overloads and type schemas thus allowing Python to be a library implementation language for bones
  • immutable updates
  • contextual scope
  • and an embryonic core library of common pipeable functions

Partial (application of) functions

By decorating a function with @coppertop (and importing _) we can easily create partial functions, for example:

syntax: f(_, a) -> f(_)
where _ is used as a sentinel place-holder for arguments yet to be confirmed (TBC)

from coppertop.pipe import *

@coppertop
def appendStr(x, y):
    assert isinstance(x, str) and isinstance(y, str)
    return x + y

appendWorld = appendStr(_, " world!")

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 easy to express the syntax (aka sequence) of a solution.


unary style - takes 1 piped argument and 0+ called arguments

syntax: A >> f(args) -> f(args)(A)

from dm.std import anon

@coppertop
def addOne(x):
    return x + 1

1 >> addOne
"hello" >> appendStr(_," ") >> appendStr(_, "world!")

1 >> anon(lambda x: x +1)

binary style - takes 2 piped argument and 0+ called arguments

syntax: A >> f(args) >> B -> f(args)(A, B)

from coppertop.core import NotYetImplemented
from dm.std import each, 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] >> each >> (lambda x: x + 1)
[1,2,3] >> inject(_,0,_) >> (lambda x,y: x + y)

ternary style - takes 3 piped argument and 0+ called arguments

syntax: A >> f(args) >> B >> C -> f(args)(A, B, C)

from dm.std import both, check, equal

[1,2] >> both >> (lambda x, y: x + y) >> [3,4] >> check >> equal >> [4, 6]

as an exercise for the reader

[1,2] >> both >> (lambda x, y: x + y) >> [3,4] 
   >> each >> (lambda x: x * 2)
   >> inject(_,1,_) >> (lambda x,y: x * y)
   >> addOne >> addOne >> addOne
   >> to(_,str) >> appendStr(" red balloons go by")
   >> check >> equal >> ???

Multiple-dispatch

Just redefine functions with different type annotations. Missing annotations are taken as fallback wildcards. Class inheritance is ignored when matching caller and function signatures.

@coppertop
def addOne(x:idx) -> idx:
    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()

1 >> addOne >> check >> equal >> 2
'Three Two ' >> addOne >> check >> equal >> 'Three Two One'
[0] >> addOne >> check >> equal >> [0, 1]

Type system

As an introduction, consider:

from ribs.types import BTAtom, S, num, idx, str, O
num = BTAtom.ensure('num')      # nominal
_ccy = BTAtom.ensure('_ccy')    # nominal
ccy = num & _ccy                # intersection
ccy + null                      # union
ccy * idx * str             # tuple (sequence of types)
S(name=str, age=num)          # struct
N ** ccy                        # collection of ccy accessed by an ordinal (N)
str ** ccy                    # collection of ccy accessed by a python string
(num*num) ^ num                 # (num, num) -> num - a function
T, T1, T2, ...                  # type variable - to be inferred at build time

I(domestic=ccy&T, foreign=ccy&T)  # named intersection (aka discrimated type)

Example - Cluedo notepad

See algos.py, where we track a game of Cluedo and make inferences for who did it. See games.py for example game input.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

coppertop-bones-2022.7.30.tar.gz (41.4 kB view details)

Uploaded Source

File details

Details for the file coppertop-bones-2022.7.30.tar.gz.

File metadata

  • Download URL: coppertop-bones-2022.7.30.tar.gz
  • Upload date:
  • Size: 41.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/4.0.1 CPython/3.9.13

File hashes

Hashes for coppertop-bones-2022.7.30.tar.gz
Algorithm Hash digest
SHA256 ce3fd6be841170979d30fa9b0b2cd244a24768c822b202074c509c3540c3f59d
MD5 0013649b32de75cf5ea221ec836cf37c
BLAKE2b-256 642e2504ec57f09370f56b3edf99b6e2c171a68414fff7616f8e60a4eb84d679

See more details on using hashes here.

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page