Monads/Maybe monad: Difference between revisions

Content added Content deleted
(A Python implementation)
Line 1,072: Line 1,072:
3 -> 19
3 -> 19
"none" -> "none"
"none" -> "none"
</pre>

=={{header|Python}}==

In this implementation, a <code>Maybe</code> type's constructor is effectively
the <code>unit</code> function. I've stopped short of implementing
<code>of</code>, <code>get</code>, <code>isPresent</code>, etc., methods that
might be familiar to those who've used the <code>Optional</code> class in Java.

Note that I've used <code>>></code> as the bind operator. Trying to chain
<code>__irshift__</code> (<code>>>=</code>) would be a syntax error.

<lang python>"""A Maybe Monad. Requires Python >= 3.7 for type hints."""
from __future__ import annotations

from typing import Any
from typing import Callable
from typing import Generic
from typing import Optional
from typing import TypeVar
from typing import TYPE_CHECKING


T = TypeVar("T")

if TYPE_CHECKING:
F = Callable[[Optional[T]], Maybe[Any]]


class Maybe(Generic[T]):
def __init__(self, value: Optional[T]):
self.value = value

def __rshift__(self, func: F):
return self.bind(func)

def bind(self, func: F) -> Maybe[Any]:
return func(self.value)

def __str__(self):
return f"{self.__class__.__name__}({self.value!r})"


def plus_one(value: Optional[int]) -> Maybe[int]:
if value is not None:
return Maybe[int](value + 1)
return Maybe[int](None)


def currency(value: Optional[int]) -> Maybe[str]:
if value is not None:
return Maybe[str](f"${value}.00")
return Maybe[str](None)


if __name__ == "__main__":
test_cases = [1, 99, None, 4]

for case in test_cases:
m_int = Maybe[int](case)
result = m_int >> plus_one >> currency
# or..
# result = m_int.bind(plus_one).bind(currency)
print(f"{str(case):<4} -> {result}")
</lang>

{{out}}
<pre>
1 -> MaybeStr('$2.00')
99 -> MaybeStr('$100.00')
None -> MaybeStr(None)
4 -> MaybeStr('$5.00')
</pre>
</pre>