ProvenPin Install

returns Maybe and IOResult railway composition with map and bind: working versions (tested 2026-10-16)

Railway-style composition over returns Maybe and IOResult: map versus bind, short-circuiting Nothing, maybe and bind_optional, impure_safe failures and IO-boxed unwrap, all tested offline.

passed6 passed · 0 failed2026-10-16 09:58 UTC
Status
passed
Last passed
2026-10-16 09:58 UTC
Tests
6 / 6
Language
Python
Runtime
Python 3.13.16
pinned versions3
returns@0.29.0typing-extensions@4.16.0pytest@9.1.1
run it
uv venv -q .venv && uv pip install -q --python .venv/bin/python -r requirements.txt
.venv/bin/python -m pytest -q
test environment
Python 3.13.16
linux 6.17.0-1022-azure
x64
runner: github-actions 38883899161

The code

Exactly the files that passed. Your agent can pull them with get_recipe("returns-maybe-ioresult") (install), or see them on GitHub.

requirements.txt
returns==0.29.0
typing-extensions==4.16.0
pytest==9.1.1
maybe_ioresult.py
from returns.io import IOResult, IOSuccess, IOFailure, impure_safe
from returns.maybe import Maybe, Nothing, Some, maybe
from returns.result import Failure, Result, Success

_TAKEN = {3, 7}


@maybe
def parse_seat(raw: str) -> int | None:
    return int(raw) if raw.isdigit() else None


def in_range(number: int) -> Maybe[int]:
    return Some(number) if 1 <= number <= 9 else Nothing


def maybe_to_result(value: Maybe[int], error: str) -> Result[int, str]:
    return value.map(Success).value_or(Failure(error))


@impure_safe
def reserve(number: int) -> str:
    if number in _TAKEN:
        raise ValueError(f"seat {number} taken")
    return f"seat-{number}"


def checkout(raw: str) -> IOResult[str, str]:
    seat = parse_seat(raw).bind(in_range)
    return IOResult.from_result(maybe_to_result(seat, f"invalid seat: {raw}")).bind(reserve)
tests/test_maybe_ioresult.py
import pytest
from returns.io import IO, IOFailure, IOSuccess
from returns.maybe import Maybe, Nothing, Some
from returns.result import Failure, Success, UnwrapFailedError

import maybe_ioresult as m


def test_some_none_is_not_nothing_but_maybe_normalizes_none():
    assert Some(None) != Nothing
    assert Maybe.from_optional(None) == Nothing
    assert m.parse_seat("x") == Nothing
    assert m.parse_seat("4") == Some(4)
    assert bool(Nothing) is False
    assert bool(Some(0)) is True


def test_map_nests_but_bind_flattens_on_maybe():
    assert Some(2).map(lambda n: Some(n + 1)) == Some(Some(3))
    assert Some(2).bind(lambda n: Some(n + 1)) == Some(3)
    assert Some(2).map(lambda n: Nothing) == Some(Nothing)
    assert Some(2).bind(lambda n: Nothing) == Nothing


def test_nothing_short_circuits_and_bind_optional_absorbs_none():
    seen = []

    def step(value):
        seen.append(value)
        return Some(value)

    assert Nothing.map(step) == Nothing
    assert Nothing.bind(step) == Nothing
    assert seen == []
    assert Some("4").bind_optional(lambda s: int(s) if s.isdigit() else None) == Some(4)
    assert Some("x").bind_optional(lambda s: int(s) if s.isdigit() else None) == Nothing


def test_impure_safe_captures_exceptions_and_io_boxes_unwrap():
    assert m.reserve(2) == IOSuccess("seat-2")
    failed = m.reserve(3)
    assert isinstance(failed, IOFailure)
    assert failed.failure()._inner_value.args == ("seat 3 taken",)
    assert failed.value_or("none") == IO("none")
    assert failed.value_or("none") != "none"
    with pytest.raises(UnwrapFailedError) as exc:
        failed.unwrap()
    assert isinstance(exc.value.__cause__, ValueError)


def test_bind_result_bridges_result_while_bind_keeps_the_io_rail():
    assert IOSuccess(2).bind_result(lambda n: Success(n + 1)) == IOSuccess(3)
    assert IOSuccess(2).bind_result(lambda n: Failure("no")) == IOFailure("no")
    assert IOSuccess(2).bind(lambda n: Success(n + 1)) == Success(3)


def test_checkout_combines_maybe_and_ioresult():
    assert m.checkout("2") == IOSuccess("seat-2")
    assert m.checkout("x") == IOFailure("invalid seat: x")
    assert m.checkout("99") == IOFailure("invalid seat: 99")
    taken = m.checkout("3")
    assert isinstance(taken, IOFailure)
    assert isinstance(taken.failure()._inner_value, ValueError)
pytest.ini
[pytest]
pythonpath = .

Connect to ProvenPin

Add the free MCP server so your agent can pull this recipe and others like it. Same setup as the docs.

terminal
claude mcp add --transport http provenpin https://mcp.provenpin.com/mcp

Any other MCP client: Streamable HTTP at https://mcp.provenpin.com/mcp. No API key, no signup.