Module grscheller.datastructures.functional.maybe

Module grscheller.datastructures.functional.maybe

Implemention of the Maybe Monad, sometimes called the Option ot Optional Monad.

Expand source code
# Copyright 2023 Geoffrey R. Scheller
# 
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
# 
#     http://www.apache.org/licenses/LICENSE-2.0
# 
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

"""Module grscheller.datastructures.functional.maybe

Implemention of the Maybe Monad, sometimes called the Option ot Optional Monad.
"""

from __future__ import annotations
from typing import Any, Callable

__all__ = ['Maybe', 'Some', 'Nothing']
__author__ = "Geoffrey R. Scheller"
__copyright__ = "Copyright (c) 2023 Geoffrey R. Scheller"
__license__ = "Appache License 2.0"

class Maybe():
    """Class representing a potentially missing value.

    - Implements the Option Monad
    - Maybe(value) constructs "Some(value)" 
    - Both Maybe() or Maybe(None) constructs a "Nothing"
    - immutable semantics - map & flatMap return modified copies
    - None is always treated as a non-existance value
      - cannot be stored in an object of type Maybe
      - semantically None does not exist
      - None only has any real existance as an implementration detail
    """
    def __init__(self, value: Any=None):
        self._value = value

    def __bool__(self) -> bool:
        """Return false if a Nothing, otherwise true."""
        return self._value != None

    def __len__(self) -> int:
        """A Maybe either contains something or not.
        Return 1 if a Some, 0 if a Nothing.
        """
        if self:
            return 1
        return 0

    def __iter__(self):
        """Yields its value if not a Nothing"""
        if self:
            yield self._value

    def __repr__(self) -> str:
        if self:
            return 'Some(' + repr(self._value) + ')'
        else:
            return 'Nothing'

    def __eq__(self, other: Maybe) -> bool:
        """Returns true if both sides are Nothings, or if both sides are Somes
        contining values which compare as equal.
        """
        if not isinstance(other, type(self)):
            return False
        return self._value == other._value

    def map(self, f: Callable[[Any], Any]) -> Maybe:
        if self:
            return Maybe(f(self._value))
        else:
            return Maybe()

    def flatMap(self, f: Callable[[Any], Maybe]) -> Maybe:
        if self:
            return f(self._value)
        else:
            return Maybe()

    def get(self, default: Any=None) -> Any:
        """Get contents if they exist, otherwise return None. Caller is
        responsible with dealing with a None return value.
        """
        if self:
            return self._value
        else:
            return default

# Maybe convenience functions/objects. Like "unit", "Nil", "()" in FP-languages.
# These are not necessary to ues Maybe, but gives Maybe the flavor of a Union
# type without using either inheritance or unnecessary internal state.

def Some(value=None):
    """Function for creating a Maybe from a value. If value is None or missing,
    returns a Nothing.
    """
    return Maybe(value)

#: Maybe object representing a missing value,
#: Nothing is not a singleton. Test via equality not identity.
Nothing = Some()

if __name__ == "__main__":
    pass

Global variables

var Nothing

Maybe object representing a missing value, Nothing is not a singleton. Test via equality not identity.

Functions

def Some(value=None)

Function for creating a Maybe from a value. If value is None or missing, returns a Nothing.

Expand source code
def Some(value=None):
    """Function for creating a Maybe from a value. If value is None or missing,
    returns a Nothing.
    """
    return Maybe(value)

Classes

class Maybe (value: Any = None)

Class representing a potentially missing value.

  • Implements the Option Monad
  • Maybe(value) constructs "Some(value)"
  • Both Maybe() or Maybe(None) constructs a "Nothing"
  • immutable semantics - map & flatMap return modified copies
  • None is always treated as a non-existance value
  • cannot be stored in an object of type Maybe
  • semantically None does not exist
  • None only has any real existance as an implementration detail
Expand source code
class Maybe():
    """Class representing a potentially missing value.

    - Implements the Option Monad
    - Maybe(value) constructs "Some(value)" 
    - Both Maybe() or Maybe(None) constructs a "Nothing"
    - immutable semantics - map & flatMap return modified copies
    - None is always treated as a non-existance value
      - cannot be stored in an object of type Maybe
      - semantically None does not exist
      - None only has any real existance as an implementration detail
    """
    def __init__(self, value: Any=None):
        self._value = value

    def __bool__(self) -> bool:
        """Return false if a Nothing, otherwise true."""
        return self._value != None

    def __len__(self) -> int:
        """A Maybe either contains something or not.
        Return 1 if a Some, 0 if a Nothing.
        """
        if self:
            return 1
        return 0

    def __iter__(self):
        """Yields its value if not a Nothing"""
        if self:
            yield self._value

    def __repr__(self) -> str:
        if self:
            return 'Some(' + repr(self._value) + ')'
        else:
            return 'Nothing'

    def __eq__(self, other: Maybe) -> bool:
        """Returns true if both sides are Nothings, or if both sides are Somes
        contining values which compare as equal.
        """
        if not isinstance(other, type(self)):
            return False
        return self._value == other._value

    def map(self, f: Callable[[Any], Any]) -> Maybe:
        if self:
            return Maybe(f(self._value))
        else:
            return Maybe()

    def flatMap(self, f: Callable[[Any], Maybe]) -> Maybe:
        if self:
            return f(self._value)
        else:
            return Maybe()

    def get(self, default: Any=None) -> Any:
        """Get contents if they exist, otherwise return None. Caller is
        responsible with dealing with a None return value.
        """
        if self:
            return self._value
        else:
            return default

Methods

def flatMap(self, f: Callable[[Any], Maybe]) ‑> Maybe
Expand source code
def flatMap(self, f: Callable[[Any], Maybe]) -> Maybe:
    if self:
        return f(self._value)
    else:
        return Maybe()
def get(self, default: Any = None) ‑> Any

Get contents if they exist, otherwise return None. Caller is responsible with dealing with a None return value.

Expand source code
def get(self, default: Any=None) -> Any:
    """Get contents if they exist, otherwise return None. Caller is
    responsible with dealing with a None return value.
    """
    if self:
        return self._value
    else:
        return default
def map(self, f: Callable[[Any], Any]) ‑> Maybe
Expand source code
def map(self, f: Callable[[Any], Any]) -> Maybe:
    if self:
        return Maybe(f(self._value))
    else:
        return Maybe()