Maybe

The Maybe container is used when a series of computations could return None at any point.

Maybe container

Maybe consist of two types: Some and Nothing. We have a convenient method to create different Maybe types based on just a single value:

>>> from returns.maybe import Maybe

>>> assert str(Maybe.from_optional(1)) == '<Some: 1>'
>>> assert str(Maybe.from_optional(None)) == '<Nothing>'

We also have another method called .from_value that behaves a bit differently:

>>> from returns.maybe import Maybe

>>> assert str(Maybe.from_value(1)) == '<Some: 1>'
>>> assert str(Maybe.from_value(None)) == '<Some: None>'

Usage

It might be very useful for complex operations like the following one:

>>> from attr import dataclass
>>> from typing import Optional
>>> from returns.maybe import Maybe, Nothing

>>> @dataclass
... class Address(object):
...     street: Optional[str]

>>> @dataclass
... class User(object):
...     address: Optional[Address]

>>> @dataclass
... class Order(object):
...     user: Optional[User]

>>> def get_street_address(order: Order) -> Maybe[str]:
...     return Maybe.from_optional(order.user).bind_optional(
...         lambda user: user.address,
...     ).bind_optional(
...         lambda address: address.street,
...     )

>>> with_address = Order(User(Address('Some street')))
>>> empty_user = Order(None)
>>> empty_address = Order(User(None))
>>> empty_street = Order(User(Address(None)))

>>> str(get_street_address(with_address))  # all fields are not None
'<Some: Some street>'

>>> assert get_street_address(empty_user) == Nothing
>>> assert get_street_address(empty_address) == Nothing
>>> assert get_street_address(empty_street) == Nothing

Optional type

One may ask: “How is that different to the Optional[] type?” That’s a really good question!

Consider the same code to get the street name without Maybe and using raw Optional values:

order: Order  # some existing Order instance
street: Optional[str] = None
if order.user is not None:
    if order.user.address is not None:
        street = order.user.address.street

It looks way uglier and can grow even more uglier and complex when new logic will be introduced.

Decorators

Limitations

Typing will only work correctly if our mypy plugin is used. This happens due to mypy issue.

maybe

Sometimes we have to deal with functions that dears to return Optional values!

We have to work with it the carefully and write if x is not None: everywhere. Luckily, we have your back! maybe function decorates any other function that returns Optional and converts it to return Maybe instead:

>>> from typing import Optional
>>> from returns.maybe import Maybe, Some, maybe

>>> @maybe
... def number(num: int) -> Optional[int]:
...     if num > 0:
...         return num
...     return None

>>> result: Maybe[int] = number(1)
>>> assert result == Some(1)

FAQ

How can I turn Maybe into Optional again?

When working with regular Python, you might need regular Optional[a] values.

You can easily get one from your Maybe container at any point in time:

>>> from returns.maybe import Maybe
>>> assert Maybe.from_optional(1).value_or(None) == 1
>>> assert Maybe.from_optional(None).value_or(None) == None

As you can see, revealed type of .value_or(None) is Optional[a]. Use it a fallback.

How to model absence of value vs presence of None value?

Let’s say you have this dict: values = {'a': 1, 'b': None} So, you can have two types of None here:

  • values.get('b')

  • values.get('c')

But, they are different! The first has explicit None value, the second one has no given key and None is used as a default. You might need to know exactly which case you are dealing with. For example, in validation.

So, the first thing to remember is that:

>>> assert Some(None) != Nothing

There’s a special way to work with a type like this:

>>> values = {'a': 1, 'b': None}

>>> assert Maybe.from_value(values).map(lambda d: d.get('a')) == Some(1)
>>> assert Maybe.from_value(values).map(lambda d: d.get('b')) == Some(None)

In contrast, you can ignore both None values easily:

>>> assert Maybe.from_value(values).bind_optional(
...     lambda d: d.get('a'),
... ) == Some(1)

>>> assert Maybe.from_value(values).bind_optional(
...     lambda d: d.get('b'),
... ) == Nothing

So, how to write a complete check for a value: both present and missing?

>>> from typing import Optional, Dict, TypeVar
>>> from returns.maybe import Maybe, Some, Nothing

>>> _Key = TypeVar('_Key')
>>> _Value = TypeVar('_Value')

>>> def check_key(
...    heystack: Dict[_Key, _Value],
...    needle: _Key,
... ) -> Maybe[_Value]:
...     if needle not in heystack:
...         return Nothing
...     return Maybe.from_value(heystack[needle])  # try with `.from_optional`

>>> real_values = {'a': 1}
>>> opt_values = {'a': 1, 'b': None}

>>> assert check_key(real_values, 'a') == Some(1)
>>> assert check_key(real_values, 'b') == Nothing
>>> # Type revealed: returns.maybe.Maybe[builtins.int]

>>> assert check_key(opt_values, 'a') == Some(1)
>>> assert check_key(opt_values, 'b') == Some(None)
>>> assert check_key(opt_values, 'c') == Nothing
>>> # Type revealed: returns.maybe.Maybe[Union[builtins.int, None]]

Choose wisely between .from_value and .map, and .from_optional and .bind_optional. They are similar, but do different things.

See the original issue about Some(None) for more details and the full history.

Why there’s no IOMaybe?

We do have IOResult, but we don’t have IOMaybe. Why? Because when dealing with IO there are a lot of possible errors. And Maybe represents just None and the value.

It is not useful for IO related tasks. So, use Result instead, which can represent what happened to your IO.

You can convert Maybe to Result and back again with special Converters.

Why Maybe does not have alt method?

Well, because Maybe only has a single failed value: Nothing and it cannot be altered.

But, Maybe has returns.maybe.Maybe.or_else_call() method to call a passed callback function with zero argument on failed container:

>>> from returns.maybe import Some, Nothing

>>> assert Some(1).or_else_call(lambda: 2) == 1
>>> assert Nothing.or_else_call(lambda: 2) == 2

This method is unique to Maybe container.

API Reference

classDiagram BaseContainer <|-- Maybe Maybe <|-- _Nothing MaybeBasedN <|-- Maybe SupportsKindN <|-- Maybe Maybe <|-- _Some
class Maybe(inner_value)[source]

Bases: returns.primitives.container.BaseContainer, returns.primitives.hkt.SupportsKindN, returns.interfaces.specific.maybe.MaybeBasedN

Represents a result of a series of computations that can return None.

An alternative to using exceptions or constant is None checks. Maybe is an abstract type and should not be instantiated directly. Instead use Some and Nothing.

empty: ClassVar[Maybe[Any]] = <Nothing>

Alias for Nothing

success_type

Success type that is used to represent the successful computation.

Parameters

inner_value (+_ValueType) –

alias of _Some

failure_type

Failure type that is used to represent the failed computation.

Parameters

inner_value (None) –

alias of _Nothing

equals(other)

Typesafe equality comparison with other Result objects.

Parameters
  • self (KindN[~_EqualType, Any, Any, Any]) –

  • other (KindN[~_EqualType, Any, Any, Any]) –

Return type

bool

map(function)[source]

Composes successful container with a pure function.

>>> from returns.maybe import Some, Nothing
>>> def mappable(string: str) -> str:
...      return string + 'b'

>>> assert Some('a').map(mappable) == Some('ab')
>>> assert Nothing.map(mappable) == Nothing
Parameters

function (Callable[[+_ValueType], ~_NewValueType]) –

Return type

Maybe[~_NewValueType]

apply(function)[source]

Calls a wrapped function in a container on this container.

>>> from returns.maybe import Some, Nothing

>>> def appliable(string: str) -> str:
...      return string + 'b'

>>> assert Some('a').apply(Some(appliable)) == Some('ab')
>>> assert Some('a').apply(Nothing) == Nothing
>>> assert Nothing.apply(Some(appliable)) == Nothing
>>> assert Nothing.apply(Nothing) == Nothing
Parameters

function (KindN[Maybe, Callable[[+_ValueType], ~_NewValueType], Any, Any]) –

Return type

Maybe[~_NewValueType]

bind(function)[source]

Composes successful container with a function that returns a container.

>>> from returns.maybe import Nothing, Maybe, Some
>>> def bindable(string: str) -> Maybe[str]:
...      return Some(string + 'b')

>>> assert Some('a').bind(bindable) == Some('ab')
>>> assert Nothing.bind(bindable) == Nothing
Parameters

function (Callable[[+_ValueType], KindN[Maybe, ~_NewValueType, Any, Any]]) –

Return type

Maybe[~_NewValueType]

bind_optional(function)[source]

Binds a function returning an optional value over a container.

>>> from returns.maybe import Some, Nothing
>>> from typing import Optional

>>> def bindable(arg: str) -> Optional[int]:
...     return len(arg) if arg else None

>>> assert Some('a').bind_optional(bindable) == Some(1)
>>> assert Some('').bind_optional(bindable) == Nothing
Parameters

function (Callable[[+_ValueType], Optional[~_NewValueType]]) –

Return type

Maybe[~_NewValueType]

lash(function)[source]

Composes failed container with a function that returns a container.

>>> from returns.maybe import Maybe, Some, Nothing

>>> def lashable(arg=None) -> Maybe[str]:
...      return Some('b')

>>> assert Some('a').lash(lashable) == Some('a')
>>> assert Nothing.lash(lashable) == Some('b')

We need this feature to make Maybe compatible with different Result like oeprations.

Parameters

function (Callable[[Any], KindN[Maybe, +_ValueType, Any, Any]]) –

Return type

Maybe[+_ValueType]

value_or(default_value)[source]

Get value from successful container or default value from failed one.

>>> from returns.maybe import Nothing, Some
>>> assert Some(0).value_or(1) == 0
>>> assert Nothing.value_or(1) == 1
Parameters

default_value (~_NewValueType) –

Return type

Union[+_ValueType, ~_NewValueType]

or_else_call(function)[source]

Get value from successful container or default value from failed one.

Really close to value_or() but works with lazy values. This method is unique to Maybe container, because other containers do have .alt method.

But, Maybe does not have this method. There’s nothing to alt in Nothing.

Instead, it has this method to execute some function if called on a failed container:

>>> from returns.maybe import Some, Nothing
>>> assert Some(1).or_else_call(lambda: 2) == 1
>>> assert Nothing.or_else_call(lambda: 2) == 2

It might be useful to work with exceptions as well:

>>> def fallback() -> NoReturn:
...    raise ValueError('Nothing!')

>>> Nothing.or_else_call(fallback)
Traceback (most recent call last):
  ...
ValueError: Nothing!
Parameters

function (Callable[[], ~_NewValueType]) –

Return type

Union[+_ValueType, ~_NewValueType]

unwrap()[source]

Get value from successful container or raise exception for failed one.

>>> from returns.maybe import Nothing, Some
>>> assert Some(1).unwrap() == 1

>>> Nothing.unwrap()
Traceback (most recent call last):
  ...
returns.primitives.exceptions.UnwrapFailedError
Return type

+_ValueType

failure()[source]

Get failed value from failed container or raise exception from success.

>>> from returns.maybe import Nothing, Some
>>> assert Nothing.failure() is None

>>> Some(1).failure()
Traceback (most recent call last):
  ...
returns.primitives.exceptions.UnwrapFailedError
Return type

None

classmethod from_value(inner_value)[source]

Creates new instance of Maybe container based on a value.

>>> from returns.maybe import Maybe, Some
>>> assert Maybe.from_value(1) == Some(1)
>>> assert Maybe.from_value(None) == Some(None)
Parameters

inner_value (~_NewValueType) –

Return type

Maybe[~_NewValueType]

classmethod from_optional(inner_value)[source]

Creates new instance of Maybe container based on an optional value.

>>> from returns.maybe import Maybe, Some, Nothing
>>> assert Maybe.from_optional(1) == Some(1)
>>> assert Maybe.from_optional(None) == Nothing
Parameters

inner_value (Optional[~_NewValueType]) –

Return type

Maybe[~_NewValueType]

Some(inner_value)[source]

Public unit function of protected _Some type.

Can return Some(None) for passed None argument. Because Some(None) does make sense.

>>> from returns.maybe import Some
>>> assert str(Some(1)) == '<Some: 1>'
>>> assert str(Some(None)) == '<Some: None>'
Parameters

inner_value (~_NewValueType) –

Return type

Maybe[~_NewValueType]

Nothing: returns.maybe.Maybe[NoReturn] = <Nothing>

Public unit value of protected _Nothing type.

maybe(function)[source]

Decorator to convert None-returning function to Maybe container.

This decorator works with sync functions only. Example:

>>> from typing import Optional
>>> from returns.maybe import Nothing, Some, maybe

>>> @maybe
... def might_be_none(arg: int) -> Optional[int]:
...     if arg == 0:
...         return None
...     return 1 / arg

>>> assert might_be_none(0) == Nothing
>>> assert might_be_none(1) == Some(1.0)

Requires our mypy plugin.

Parameters

function (Callable[…, Optional[+_ValueType]]) –

Return type

Callable[…, Maybe[+_ValueType]]

Interfaces Result