monadcontainers.monads API documentation

# monadcontainers.monads

View Source

      1from typing import Any, Callable, Generic
      2from typing import List as ListType
      3from typing import Optional, Type, TypeVar, Union
      4
      5T = TypeVar("T")
      6U = TypeVar("U")
      7
      8
      9class Monad(Generic[T]):
     10    """
     11    Identity monad (also the parent class for all other monads).
     12
     13    No additional work is handled on function calls, apart from returning
     14    a new monad with an updated result.
     15
     16    Can be used like so:
     17
     18    ```python
     19    def make_loud(x:str) -> str:
     20        return x.upper()
     21
     22    x = Monad("hello world!") >> make_loud
     23
     24    print(x.value)
     25    # prints out "HELLO WORLD!"
     26    ```
     27    """
     28    def __init__(self: Any, value: T) -> None:
     29        """
     30        Initialise a monad with the given value
     31        """
     32        self.value: T = value
     33
     34    def bind(self, func) -> "Monad":
     35        """
     36        Method to apply function to value of Monad.
     37        Returns a monad with the updated value.
     38
     39        Example:
     40        ```python
     41        Monad(2).bind(lambda x: x+1) == Monad(3)
     42        ```
     43
     44        Can be aliased with `>>` symbol:
     45        ```python
     46        (Monad(2) >> (lambda x: x+1)) == Monad(3)
     47        """
     48        return Monad(func(self.value))
     49
     50    def __rshift__(self, other) -> "Monad":
     51        """
     52        Dunder method to alias bind into >>
     53        """
     54        return self.bind(other)
     55
     56    def unwrap(self) -> T:
     57        """
     58        Return only the value of the monad without wrapping
     59        it.
     60
     61        ```python
     62        Monad(4).unwrap() == 4
     63        ```
     64        """
     65        return self.value
     66
     67    def __str__(self) -> str:
     68        """
     69        String representation
     70        """
     71        return f"{self.__class__.__name__}({self.value})"
     72
     73    def __repr__(self) -> str:
     74        """
     75        For repls
     76        """
     77        return self.__str__()
     78
     79
     80class Maybe(Monad, Generic[T]):
     81    """
     82    Monad to handle None values.
     83
     84    Write functions as if they can't recieve None values.
     85    If Monad value is None, it will skip execution of function
     86    and remain as None.
     87
     88    None example:
     89    ```python
     90    Maybe(None) >> (lambda x: x + 4)  # will remain None
     91    ```
     92    """
     93    def bind(self, func: Callable) -> "Maybe":
     94        """
     95        Execute function on value, unless None
     96        (in which case return None monad)
     97        """
     98        if self.value is None:
     99            return Maybe(None)
    100        return Maybe(func(self.value))
    101
    102
    103class List(Monad, Generic[T]):
    104    """
    105    Monad to apply function to all items in list.
    106
    107    Write functions as if they act on a single value.
    108
    109    Example:
    110    ```python
    111    x = (
    112        List([1, 3, 7])
    113        >> (lambda x: x + 1)
    114        >> (lambda x: x / 2)
    115    )
    116    # x will evaluate to List([1, 2, 4])
    117    """
    118    def __init__(self: Any, value: ListType[T]) -> None:
    119        """
    120        Initialise a monad with the given list
    121        """
    122        self.value: ListType[T] = value
    123
    124    def bind(self, func: Callable) -> "List":
    125        """
    126        Map function on every element of list:
    127
    128        ```python
    129        def make_exciting(text: str) -> str:
    130            return test.upper() + "!!!"
    131
    132        fun_stuff = (
    133            List(["hats", "cats", "bats"])
    134            >> make_exciting
    135        ).unwrap()
    136
    137        fun_stuff == ["HATS!!!", "CATS!!!", "BATS!!!"]
    138        """
    139        return List([func(x) for x in self.value])
    140
    141    def filter(self, func: Callable) -> "List":
    142        """
    143        Filter list to only elements with true return:
    144
    145        ```python
    146        x = (
    147            List([1, 2, 3, 4])
    148            .filter(lambda x: x % 2 == 0)
    149        ).unwrap()
    150
    151        x == [2, 4]
    152        """
    153        return List([i for i in self.value if func(i)])
    154
    155    def unwrap(self) -> ListType[T]:
    156        """
    157        Return only the value of the monad without wrapping
    158        it.
    159
    160        ```python
    161        List([4]).unwrap() == [4]
    162        ```
    163        """
    164        return self.value
    165
    166
    167class Result(Monad, Generic[T]):
    168    """
    169    Monad to handle errors. Handle exceptions on unwrap:
    170
    171    ```python
    172    x = (
    173        Result(3)
    174        >> (lamba x / 0)
    175    )
    176
    177    x.value == None
    178    isinstance(x.exception, ZeroDivisionError)
    179    x.unwrap_or(4) == 4
    180    ```
    181    """
    182    def __init__(self, value: T, exception: Optional[Type[Exception]] = None):
    183        """
    184        Create Result monad with value and exception
    185        (one of which will always be None)
    186        """
    187        self.value: T = value
    188        self.exception = exception
    189
    190    def bind(self, func):
    191        """
    192        Execute function on value, if error is raised,
    193        returned Monad will have value of "None" and an exception.
    194
    195        Otherwise, exception will be None, and value will be return.
    196
    197        If exception already exists, function won't be executed.
    198        """
    199        if self.exception:
    200            return self
    201        try:
    202            return Result(func(self.value))
    203        except Exception as exception:
    204            return Result(None, exception)
    205
    206    def unwrap(self) -> T:
    207        """
    208        If exception is raised, will raise exception.
    209        Otherwise will evaluate to value.
    210        """
    211        if self.exception:
    212            raise self.exception
    213        return self.value
    214
    215    def unwrap_or(self, value: U) -> Union[T, U]:
    216        """
    217        If exception is raised, will default to given value.
    218        """
    219        if self.exception:
    220            return value
    221        return self.value
    222
    223    def __str__(self) -> str:
    224        """
    225        Custom string representation
    226        """
    227        return f"{self.__class__.__name__}({self.exception or self.value})"

class Monad(typing.Generic[~T]): View Source

    10class Monad(Generic[T]):
    11    """
    12    Identity monad (also the parent class for all other monads).
    13
    14    No additional work is handled on function calls, apart from returning
    15    a new monad with an updated result.
    16
    17    Can be used like so:
    18
    19    ```python
    20    def make_loud(x:str) -> str:
    21        return x.upper()
    22
    23    x = Monad("hello world!") >> make_loud
    24
    25    print(x.value)
    26    # prints out "HELLO WORLD!"
    27    ```
    28    """
    29    def __init__(self: Any, value: T) -> None:
    30        """
    31        Initialise a monad with the given value
    32        """
    33        self.value: T = value
    34
    35    def bind(self, func) -> "Monad":
    36        """
    37        Method to apply function to value of Monad.
    38        Returns a monad with the updated value.
    39
    40        Example:
    41        ```python
    42        Monad(2).bind(lambda x: x+1) == Monad(3)
    43        ```
    44
    45        Can be aliased with `>>` symbol:
    46        ```python
    47        (Monad(2) >> (lambda x: x+1)) == Monad(3)
    48        """
    49        return Monad(func(self.value))
    50
    51    def __rshift__(self, other) -> "Monad":
    52        """
    53        Dunder method to alias bind into >>
    54        """
    55        return self.bind(other)
    56
    57    def unwrap(self) -> T:
    58        """
    59        Return only the value of the monad without wrapping
    60        it.
    61
    62        ```python
    63        Monad(4).unwrap() == 4
    64        ```
    65        """
    66        return self.value
    67
    68    def __str__(self) -> str:
    69        """
    70        String representation
    71        """
    72        return f"{self.__class__.__name__}({self.value})"
    73
    74    def __repr__(self) -> str:
    75        """
    76        For repls
    77        """
    78        return self.__str__()

Identity monad (also the parent class for all other monads).

No additional work is handled on function calls, apart from returning a new monad with an updated result.

Can be used like so:

    def make_loud(x:str) -> str:
        return x.upper()

    x = Monad("hello world!") >> make_loud

    print(x.value)
    # prints out "HELLO WORLD!"

Monad(value: ~T) View Source

    29    def __init__(self: Any, value: T) -> None:
    30        """
    31        Initialise a monad with the given value
    32        """
    33        self.value: T = value

Initialise a monad with the given value

value: ~T
def bind(self, func) -> Monad: View Source

    35    def bind(self, func) -> "Monad":
    36        """
    37        Method to apply function to value of Monad.
    38        Returns a monad with the updated value.
    39
    40        Example:
    41        ```python
    42        Monad(2).bind(lambda x: x+1) == Monad(3)
    43        ```
    44
    45        Can be aliased with `>>` symbol:
    46        ```python
    47        (Monad(2) >> (lambda x: x+1)) == Monad(3)
    48        """
    49        return Monad(func(self.value))

Method to apply function to value of Monad. Returns a monad with the updated value.

Example:

    Monad(2).bind(lambda x: x+1) == Monad(3)

Can be aliased with `>>` symbol: ```python (Monad(2) >> (lambda x: x+1)) == Monad(3)

def unwrap(self) -> ~T: View Source

    57    def unwrap(self) -> T:
    58        """
    59        Return only the value of the monad without wrapping
    60        it.
    61
    62        ```python
    63        Monad(4).unwrap() == 4
    64        ```
    65        """
    66        return self.value

Return only the value of the monad without wrapping it.

    Monad(4).unwrap() == 4

class Maybe(Monad, typing.Generic[~T]): View Source

     81class Maybe(Monad, Generic[T]):
     82    """
     83    Monad to handle None values.
     84
     85    Write functions as if they can't recieve None values.
     86    If Monad value is None, it will skip execution of function
     87    and remain as None.
     88
     89    None example:
     90    ```python
     91    Maybe(None) >> (lambda x: x + 4)  # will remain None
     92    ```
     93    """
     94    def bind(self, func: Callable) -> "Maybe":
     95        """
     96        Execute function on value, unless None
     97        (in which case return None monad)
     98        """
     99        if self.value is None:
    100            return Maybe(None)
    101        return Maybe(func(self.value))

Monad to handle None values.

Write functions as if they can't recieve None values. If Monad value is None, it will skip execution of function and remain as None.

None example:

    Maybe(None) >> (lambda x: x + 4)  # will remain None

##### Inherited Members

Monad
  Monad
  value
  bind
  unwrap

class List(Monad, typing.Generic[~T]): View Source

    104class List(Monad, Generic[T]):
    105    """
    106    Monad to apply function to all items in list.
    107
    108    Write functions as if they act on a single value.
    109
    110    Example:
    111    ```python
    112    x = (
    113        List([1, 3, 7])
    114        >> (lambda x: x + 1)
    115        >> (lambda x: x / 2)
    116    )
    117    # x will evaluate to List([1, 2, 4])
    118    """
    119    def __init__(self: Any, value: ListType[T]) -> None:
    120        """
    121        Initialise a monad with the given list
    122        """
    123        self.value: ListType[T] = value
    124
    125    def bind(self, func: Callable) -> "List":
    126        """
    127        Map function on every element of list:
    128
    129        ```python
    130        def make_exciting(text: str) -> str:
    131            return test.upper() + "!!!"
    132
    133        fun_stuff = (
    134            List(["hats", "cats", "bats"])
    135            >> make_exciting
    136        ).unwrap()
    137
    138        fun_stuff == ["HATS!!!", "CATS!!!", "BATS!!!"]
    139        """
    140        return List([func(x) for x in self.value])
    141
    142    def filter(self, func: Callable) -> "List":
    143        """
    144        Filter list to only elements with true return:
    145
    146        ```python
    147        x = (
    148            List([1, 2, 3, 4])
    149            .filter(lambda x: x % 2 == 0)
    150        ).unwrap()
    151
    152        x == [2, 4]
    153        """
    154        return List([i for i in self.value if func(i)])
    155
    156    def unwrap(self) -> ListType[T]:
    157        """
    158        Return only the value of the monad without wrapping
    159        it.
    160
    161        ```python
    162        List([4]).unwrap() == [4]
    163        ```
    164        """
    165        return self.value

Monad to apply function to all items in list.

Write functions as if they act on a single value.

Example: ```python x = ( List([1, 3, 7])

> > (lambda x: x + 1) (lambda x: x / 2) )

> > # x will evaluate to List([1, 2, 4])

def filter(self, func: Callable) -> List: View Source

    142    def filter(self, func: Callable) -> "List":
    143        """
    144        Filter list to only elements with true return:
    145
    146        ```python
    147        x = (
    148            List([1, 2, 3, 4])
    149            .filter(lambda x: x % 2 == 0)
    150        ).unwrap()
    151
    152        x == [2, 4]
    153        """
    154        return List([i for i in self.value if func(i)])

Filter list to only elements with true return:

```python x = ( List([1, 2, 3, 4]) .filter(lambda x: x % 2 == 0) ).unwrap()

x == [2, 4]

##### Inherited Members

Monad
  Monad
  value
  bind
  unwrap

class Result(Monad, typing.Generic[~T]): View Source

    168class Result(Monad, Generic[T]):
    169    """
    170    Monad to handle errors. Handle exceptions on unwrap:
    171
    172    ```python
    173    x = (
    174        Result(3)
    175        >> (lamba x / 0)
    176    )
    177
    178    x.value == None
    179    isinstance(x.exception, ZeroDivisionError)
    180    x.unwrap_or(4) == 4
    181    ```
    182    """
    183    def __init__(self, value: T, exception: Optional[Type[Exception]] = None):
    184        """
    185        Create Result monad with value and exception
    186        (one of which will always be None)
    187        """
    188        self.value: T = value
    189        self.exception = exception
    190
    191    def bind(self, func):
    192        """
    193        Execute function on value, if error is raised,
    194        returned Monad will have value of "None" and an exception.
    195
    196        Otherwise, exception will be None, and value will be return.
    197
    198        If exception already exists, function won't be executed.
    199        """
    200        if self.exception:
    201            return self
    202        try:
    203            return Result(func(self.value))
    204        except Exception as exception:
    205            return Result(None, exception)
    206
    207    def unwrap(self) -> T:
    208        """
    209        If exception is raised, will raise exception.
    210        Otherwise will evaluate to value.
    211        """
    212        if self.exception:
    213            raise self.exception
    214        return self.value
    215
    216    def unwrap_or(self, value: U) -> Union[T, U]:
    217        """
    218        If exception is raised, will default to given value.
    219        """
    220        if self.exception:
    221            return value
    222        return self.value
    223
    224    def __str__(self) -> str:
    225        """
    226        Custom string representation
    227        """
    228        return f"{self.__class__.__name__}({self.exception or self.value})"

Monad to handle errors. Handle exceptions on unwrap:

    x = (
        Result(3)
        >> (lamba x / 0)
    )

    x.value == None
    isinstance(x.exception, ZeroDivisionError)
    x.unwrap_or(4) == 4

exception
def unwrap_or(self, value: ~U) -> Union[~T, ~U]: View Source

    216    def unwrap_or(self, value: U) -> Union[T, U]:
    217        """
    218        If exception is raised, will default to given value.
    219        """
    220        if self.exception:
    221            return value
    222        return self.value

If exception is raised, will default to given value.

##### Inherited Members

Monad
  Monad
  value
  bind
  unwrap