Monads/List monad: Difference between revisions

A Python implementation
(A Python implementation)
Line 619:
<pre>
{3,4,5} -> {8,10,12}
</pre>
 
=={{header|Python}}==
 
<lang python>"""A List Monad. Requires Python >= 3.7 for type hints."""
from __future__ import annotations
from itertools import chain
 
from typing import Any
from typing import Callable
from typing import Iterable
from typing import List
from typing import TypeVar
 
 
T = TypeVar("T")
 
 
class MList(List[T]):
@classmethod
def unit(cls, value: Iterable[T]) -> MList[T]:
return cls(value)
 
def bind(self, func: Callable[[T], MList[Any]]) -> MList[Any]:
return MList(chain.from_iterable(map(func, self)))
 
def __rshift__(self, func: Callable[[T], MList[Any]]) -> MList[Any]:
return self.bind(func)
 
 
if __name__ == "__main__":
# Chained int and string functions
print(
MList([1, 99, 4])
.bind(lambda val: MList([val + 1]))
.bind(lambda val: MList([f"${val}.00"]))
)
 
# Same, but using `>>` as the bind operator.
print(
MList([1, 99, 4])
>> (lambda val: MList([val + 1]))
>> (lambda val: MList([f"${val}.00"]))
)
 
# Cartesian product of [1..5] and [6..10]
print(
MList(range(1, 6)).bind(
lambda x: MList(range(6, 11)).bind(lambda y: MList([(x, y)]))
)
)
 
# Pythagorean triples with elements between 1 and 25
print(
MList(range(1, 26)).bind(
lambda x: MList(range(x + 1, 26)).bind(
lambda y: MList(range(y + 1, 26)).bind(
lambda z: MList([(x, y, z)])
if x * x + y * y == z * z
else MList([])
)
)
)
)
</lang>
 
{{out}}
<pre>
['$2.00', '$100.00', '$5.00']
['$2.00', '$100.00', '$5.00']
[(1, 6), (1, 7), (1, 8), (1, 9), (1, 10), (2, 6), (2, 7), (2, 8), (2, 9), (2, 10), (3, 6), (3, 7), (3, 8), (3, 9), (3, 10), (4, 6), (4, 7), (4, 8), (4, 9), (4, 10), (5, 6), (5, 7), (5, 8), (5, 9), (5, 10)]
[(3, 4, 5), (5, 12, 13), (6, 8, 10), (7, 24, 25), (8, 15, 17), (9, 12, 15), (12, 16, 20), (15, 20, 25)]
</pre>
 
140

edits