Skip to main content

Type-safe Monads

Build Status codecov Code style: black

This is an experiment in building monads in Python supported by strict type annotations. The goal is to be able to compose monads with the type checker ensuring their correctness.

Motivation

I'm a fan of monads, but believe they work best with the support of a strong type system. I've attempted to use libraries like PyMonad, but been frustrated by a lack of type constraints preventing incorrect usage. I could've attempted to add type annotations to one of those libraries, but building my own is more fun.

Base Classes

Functor

map (*)

Applies a function to the contents of a functor, transforming it from one thing to another.

The * operator implements map on functors, and is both left and right associative:

def wordcount(s: str):
    return len(s.split())


f.map(wordcount) == wordcount * f == f * wordcount

Applicative

Extends Functor.

pure

Wraps a value in an applicative functor.

e.g.:

Maybe.pure("abc") == Just("abc")
Result.pure(123) == Ok(123)

apply (&)

Transforms the value contained in the instance's functor with a function wrapped in the same type of functor.

The & operator implements apply on applicatives, and is right-associative.

e.g.:

increment = lambda x: x + 1

Just(3).apply(Just(increment)) == Just(increment) & Just(3) == Just(4)

This can be very handily combined with map to apply curried functions to multiple arguments:

subtract = lambda x: lambda y: x - y

subtract * Just(10) & Just(4) == Just(6)

Monad

Extends Applicative.

bind (>>)

Passes the value within the monad through an operation returning the same type of monad, allowing multiple operations to be chained.

The >> operator implements bind on monads, and is left-associative.

@curry
def lookup(key: str, dictionary: Dict[str, str]) -> Maybe[str]:
    try:
        return Just(dictionary[key])
    except KeyError:
        return Nothing()


result = Just({"hello": "world"}).bind(lookup("hello")).bind(lambda s: s.upper())
result = (
    Just({"hello": "world"})
    >> lookup("hello")
    >> (lambda s: s.upper())
)

Monoid

mappend (+)

Describes an associative binary operation for a type.

mzero

Provides an identity value for the mappend operation.

mconcat

Accumulates a list of values using mappend. Returns the mzero value if the list is empty.

Monads

Maybe[T]

Represents optional data. A Maybe instance of a certain type T will either be a Just object wrapping a value of that type, or Nothing.

  • Mapping a function over Nothing will return Nothing without calling the function.
  • Binding an operation with a Nothing will return Nothing without attempting the operation.

Result[T, E]

Represents a state of success or failure, declaring a type for each. A Result instance will either be an Ok object wrapping a value of the success type T, or an Err object wrapping a value of the failure type E.

  • Mapping a function over an Err will return the Err unchanged without calling the function.
  • Binding an operation with an Err will return the Err unchanged without attempting the operation.

List[T]

Represents a sequence of items.

  • Also implements Monoid.

Future[T]

Represents an asynchronous action.

  • Also implements Awaitable.

Reader[T]

Represents the application of a function to it's argument.

Metadata

Release files for typesafe-monads 0.8

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for typesafe-monads 0.8
File Size Uploaded Provenance Actions
typesafe-monads-0.8.tar.gz 9.4 kB Without provenance Details for typesafe-monads-0.8.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for typesafe-monads 0.8
File Interpreter ABI Platform Actions
typesafe_monads-0.8-py3-none-any.whl Python 3 none any Details for typesafe_monads-0.8-py3-none-any.whl

Total release size: 22.0 kB

Release files / typesafe-monads-0.8.tar.gz

Download URL typesafe-monads-0.8.tar.gz
Size 9.4 kB
Tags Source
SHA-256 checksum
How to use checksums
1fb44a89587c737ce37e2f7dfb0e7e755a1029be9a6aeca75c8a80d8e06ebf69
BLAKE2b-256 checksum
How to use checksums
4b831b34bc0aca3688844465c4908d16bcc798fb496006ab8a0c19042ab753e3
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/1.13.0 pkginfo/1.5.0.1 requests/2.22.0 setuptools/41.0.1 requests-toolbelt/0.9.1 tqdm/4.32.1 CPython/3.7.1

Release files / typesafe_monads-0.8-py3-none-any.whl

Download URL typesafe_monads-0.8-py3-none-any.whl
Size 12.6 kB
Tags Python 3
SHA-256 checksum
How to use checksums
157f2685951578d1040af6a9909576972e5c3f3b5184b4649b6923d5ffa84755
BLAKE2b-256 checksum
How to use checksums
04e4af1967e56e0791550e57e1b36ecfc2c3990d88740ee96ece37f68985d2c4
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/1.13.0 pkginfo/1.5.0.1 requests/2.22.0 setuptools/41.0.1 requests-toolbelt/0.9.1 tqdm/4.32.1 CPython/3.7.1

Security for typesafe-monads 0.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.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page