Skip to main content

Multiple and Predicative Dispatch

Project description

Multiple and Predicative Dispatch

This module enables extensible and context-sensitive dispatch to different code implementations that depend both on the annotated type of arguments and on predicates that are fulfilled by arguments.

Specifically, these dispatch decisions are arranged in a manner different than with blocks of if/elif or match/case statements, and also differently from inheritance hierarchies that resolve to a narrowest descendant type containing a given method.

Numerous developers have created a version of a multimethods for Python (see History of Dispatch Concepts). Most or all of those use decorators, or other conventions, to attach multiple implementations to the same global name, and switch between implentations at call time within an ordinary-looking function.

I have decided here on a slightly different API. A "dispatcher" is a namespace in which multiple callable names may live, and calling each one makes a runtime dispatch decision. The general intention in this design is that these namespaces (classes, behind the scenes) can associate related functionality, and the collection of names and implementations in a namespace can all be imported by importing the one namespace object.

A default dispatcher named Dispatcher can be imported directly, but normally a factory function will generate new ones. In the API example below, the namespace created is called nums (e.g. for numeric functions with multiple implementations), but a real problem might create others called strings or events or datasets.

The advantage of having a namespace object that maintains dispatchable implementations is that that object itself is indefinitely extensible. Within your application code that imports, e.g., the num namespace object, you can add many new function names and/or implementations for the already defined names.

API

The full API documentation will have more details. A quick example might motivate usage.

from __future__ import annotations
from math import sqrt

from dispatch.dispatch import get_dispatcher
from primes import akw_primality, mr_primality, primes_16bit
nums = get_dispatcher("nums")

@nums
def is_prime(n: int & 0 < n < 2**16) -> bool:
    "Check primes from pre-computed list"
    return n in primes_16bit

@nums
def is_prime(n: 0 < n < 2**32) -> bool:
    "Check prime factors for n < √2³²"
    ceil = sqrt(n)
    for prime in primes_16bit:
        if prime > ceil:
            return True
        if n % prime == 0:
            return False
    return True

@nums(name="is_prime")
def miller_rabin(
    n: int & n >= 2**32, 
    confidence: float = 0.999_999,
) -> bool:
    "Use Miller-Rabin pseudo-primality test"
    return mr_primality(n, confidence)

@nums(name="is_prime")
def agrawal_kayal_saxena(
    n: int & n >= 2**32,
    confidence: float & confidence == 1.0,
) -> bool:
    "Use Agrawal-Kayal-Saxena deterministic primality test"
    return aks_primality(n)

# Bind to the Gaussian prime function (which _has_ a type annotation)
nums(name="is_prime")(gaussian_prime)  

@nums
def is_twin_prime(n: int):
    "Check if n is part of a twin prime pair"
    return nums.is_prime(n) and (nums.is_prime(n + 2) or nums.is_prime(n - 2))

nums.is_prime(64_489)                        # True by direct search
nums.is_prime(64_487)                        # False by direct search
nums.is_prime(262_147)                       # True by trial division
nums.is_prime(262_143)                       # False by trial division
nums.is_prime(4_294_967_311)                 # True by Miller-Rabin test
nums.is_prime(4_294_967_309)                 # False by Miller-Rabin test
nums.is_prime(4_294_967_311, confidence=1.0) # True by AKS test
nums.is_prime(4_294_967_309, confidence=1.0) # False by AKS test
nums.is_prime(-4 + 5j)                       # True by Gaussian prime test
nums.is_prime(+4 - 7j)                       # False by Gaussian prime test
nums.is_twin_prime(617)                      # True (smaller of two)
nums.is_twin_prime(619)                      # True (larger of two)
nums.is_twin_prime(621)                      # False (not a prime)
nums.is_twin_prime(631)                      # False (not a twin)

print(nums) # -->
# nums with 2 function bound to 6 implementations (0 extra types)
nums.describe() # -->
# nums bound implementations:
# (0) is_prime
#     n: int ∩ 0 < n < 2 ** 16
# (1) is_prime
#     n: Any ∩ n < 2 ** 32
# (2) is_prime (re-bound 'miller_rabin')
#     n: int ∩ n >= 2 ** 32
#     confidence: float ∩ True
# (3) is_prime (re-bound 'agrawal_kayal_saxena')
#     n: int ∩ n >= 2 ** 32
#     confidence: float ∩ confidence == 1.0
# (0) is_twin_prime
#     n: int ∩ True

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

gnosis_dispatch-0.9.1.tar.gz (44.4 MB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

gnosis_dispatch-0.9.1-py3-none-any.whl (10.2 kB view details)

Uploaded Python 3

File details

Details for the file gnosis_dispatch-0.9.1.tar.gz.

File metadata

  • Download URL: gnosis_dispatch-0.9.1.tar.gz
  • Upload date:
  • Size: 44.4 MB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for gnosis_dispatch-0.9.1.tar.gz
Algorithm Hash digest
SHA256 577489fb79a144861b35b396f7e460d17efa22fa531d606df889cbb777238df4
MD5 4d2f29577195343b4d3fa9de7bb89daf
BLAKE2b-256 8a817601acdd955fed44eaeacb42af3208294bbdcbcb0419d443a315acb379b6

See more details on using hashes here.

File details

Details for the file gnosis_dispatch-0.9.1-py3-none-any.whl.

File metadata

File hashes

Hashes for gnosis_dispatch-0.9.1-py3-none-any.whl
Algorithm Hash digest
SHA256 0d57a749494e126d0cb43761a5036d7264d7ec0d42ecab2fe4f5022ee386d670
MD5 36817dc0a35f2342cb555b9228b52e01
BLAKE2b-256 baaa9c5a959a068ba6243925dbaecdc2c52ae991fb461bbd327400cba0d1aa81

See more details on using hashes here.

Supported by

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