Type-safe Monads
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
Nothingwill returnNothingwithout calling the function. - Binding an operation with a
Nothingwill returnNothingwithout 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
Errwill return theErrunchanged without calling the function. - Binding an operation with an
Errwill return theErrunchanged 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)
| 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)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| 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.