# Path: oslash/typing/functor.py
# class Functor(Protocol[TSource]):
#     """The Functor class is used for types that can be mapped over.
# 
#     Instances of Functor should satisfy the following laws:
# 
#     Haskell:
#     fmap id  ==  id
#     fmap (f . g)  ==  fmap f . fmap g
# 
#     Python:
#     x.map(id) == id(x)
#     x.map(compose(f, g)) == x.map(g).map(f)
# 
#     The instances of Functor for lists, Maybe and IO satisfy these laws.
#     """
# 
#     @abstractmethod
#     def map(self, fn: Callable[[TSource], TResult]) -> 'Functor[TResult]':
#         """Map a function over wrapped values.
# 
#         Map knows how to apply functions to values that are wrapped in
#         a context.
#         """
#         raise NotImplementedError
# 
#     # def __rmod__(self, fn):
#     #     """Infix version of map.
# 
#     #     Haskell: <$>
# 
#     #     Example:
#     #     >>> (lambda x: x+2) % Just(40)
#     #     42
# 
#     #     Returns a new Functor.
#     #     """
#     #     return self.map(fn)
# 
# Path: oslash/typing/monad.py
# class Monad(Protocol[TSource]):
#     """Monad protocol"""
# 
#     @abstractmethod
#     def bind(self, fn: Callable[[TSource], 'Monad[TResult]']) -> 'Monad[TResult]':
#         """Monad bind method.
# 
#         Python: bind(self: Monad[A], func: Callable[[A], Monad[B]]) -> Monad[B]
#         Haskell: (>>=) :: m a -> (a -> m b) -> m b
# 
#         This is the mother of all methods. It's hard to describe what it
#         does, because it can be used for pretty much anything:
# 
#         * Transformation, for projecting Monadic values and functions.
#         * Composition, for composing monadic functions.
#         * Chaining, for chaining of functions as a monadic value.
#         * Combining, for combining monadic values.
#         * Sequencing, of Monadic functions.
#         * Flattening, of nested Monadic values.
#         * Variable substitution, assign values to variables.
# 
#         The Monad doesn’t specify what is happening, only that whatever
#         is happening satisfies the laws of associativity and identity.
# 
#         Returns a new Monad.
#         """
#         raise NotImplementedError
# 
#     @classmethod
#     @abstractmethod
#     def unit(value: TSource) -> 'Monad[TSource]':
#         """Wrap a value in a default context.
# 
#         Haskell: return :: a -> m a .
# 
#         Inject a value into the monadic type. Since return is a reserved
#         word in Python, we align with Scala and use the name unit
#         instead.
#         """
#         raise NotImplementedError
# 
#     #def lift(self, func: Callable) -> Monad[B]:
#     #    """Map function over monadic value.
#     #
#     #    Takes a function and a monadic value and maps the function over the
#     #    monadic value
#     #
#     #    Haskell: liftM :: (Monad m) => (a -> b) -> m a -> m b
#     #
#     #    This is really the same function as Functor.fmap, but is instead
#     #    implemented using bind, and does not rely on us inheriting from
#     #    Functor.
#     #    """
#     #
#     #    return self.bind(lambda x: Monad.unit(func(x)))
# 
# 
#     #def join(self):
#     #    """join :: Monad m => m (m a) -> m a
#     #
#     #    The join function is the conventional monad join operator. It is
#     #    used to remove one level of monadic structure, projecting its
#     #    bound argument into the outer level."""
# 
#     #    return self.bind(identity)
# 
# Path: oslash/typing/monoid.py
# class Monoid(Protocol[TSource]):
#     """The Monoid abstract base class.
# 
#     The class of monoids (types with an associative binary operation that
#     has an identity). Instances should satisfy the following laws:
# 
#     mappend mempty x = x
#     mappend x mempty = x
#     mappend x (mappend y z) = mappend (mappend x y) z
#     mconcat = foldr mappend mempty
#     """
# 
#     @classmethod
#     @abstractmethod
#     def empty(cls) -> 'Monoid[TSource]':
#         """Create empty monoid.
# 
#         Haskell: mempty :: m
# 
#         The empty element and identity of append.
#         """
# 
#         raise NotImplementedError
# 
#     def __add__(self, other):
#         """Append other monoid to this monoid.
# 
#         Haskell: mappend :: m -> m -> m
# 
#         An associative operation
#         """
#         raise NotImplementedError


from typing import Callable, Tuple, Any, TypeVar, Generic, Union, cast
from .typing import Functor
from .typing import Monad
from .typing import Monoid

    @classmethod
    def unit(cls, value: TSource) -> 'Writer[TSource, TLog]':
        """Wrap a single value in a Writer.

        Use the factory method to create *Writer classes that
        uses a different monoid than str, or use the constructor
        directly.
        """
        return Writer(value, log=cast(TLog, ""))

    def run(self) -> Tuple[TSource, TLog]:
        """Extract value from Writer.

        This is the inverse function of the constructor and converts the
        Writer to s simple tuple.
        """
        return self._value

    @staticmethod
    def apply_log(a: tuple, func: Callable[[Any], Tuple[TSource, TLog]]) -> Tuple[TSource, TLog]:
        """Apply a function to a value with a log.

        Helper function to apply a function to a value with a log tuple.
        """
        value, log = a
        new, entry = func(value)
        return new, log + entry

    @classmethod

# Path: oslash/typing/functor.py
# class Functor(Protocol[TSource]):
#     """The Functor class is used for types that can be mapped over.
# 
#     Instances of Functor should satisfy the following laws:
# 
#     Haskell:
#     fmap id  ==  id
#     fmap (f . g)  ==  fmap f . fmap g
# 
#     Python:
#     x.map(id) == id(x)
#     x.map(compose(f, g)) == x.map(g).map(f)
# 
#     The instances of Functor for lists, Maybe and IO satisfy these laws.
#     """
# 
#     @abstractmethod
#     def map(self, fn: Callable[[TSource], TResult]) -> 'Functor[TResult]':
#         """Map a function over wrapped values.
# 
#         Map knows how to apply functions to values that are wrapped in
#         a context.
#         """
#         raise NotImplementedError
# 
#     # def __rmod__(self, fn):
#     #     """Infix version of map.
# 
#     #     Haskell: <$>
# 
#     #     Example:
#     #     >>> (lambda x: x+2) % Just(40)
#     #     42
# 
#     #     Returns a new Functor.
#     #     """
#     #     return self.map(fn)
# 
# Path: oslash/typing/monad.py
# class Monad(Protocol[TSource]):
#     """Monad protocol"""
# 
#     @abstractmethod
#     def bind(self, fn: Callable[[TSource], 'Monad[TResult]']) -> 'Monad[TResult]':
#         """Monad bind method.
# 
#         Python: bind(self: Monad[A], func: Callable[[A], Monad[B]]) -> Monad[B]
#         Haskell: (>>=) :: m a -> (a -> m b) -> m b
# 
#         This is the mother of all methods. It's hard to describe what it
#         does, because it can be used for pretty much anything:
# 
#         * Transformation, for projecting Monadic values and functions.
#         * Composition, for composing monadic functions.
#         * Chaining, for chaining of functions as a monadic value.
#         * Combining, for combining monadic values.
#         * Sequencing, of Monadic functions.
#         * Flattening, of nested Monadic values.
#         * Variable substitution, assign values to variables.
# 
#         The Monad doesn’t specify what is happening, only that whatever
#         is happening satisfies the laws of associativity and identity.
# 
#         Returns a new Monad.
#         """
#         raise NotImplementedError
# 
#     @classmethod
#     @abstractmethod
#     def unit(value: TSource) -> 'Monad[TSource]':
#         """Wrap a value in a default context.
# 
#         Haskell: return :: a -> m a .
# 
#         Inject a value into the monadic type. Since return is a reserved
#         word in Python, we align with Scala and use the name unit
#         instead.
#         """
#         raise NotImplementedError
# 
#     #def lift(self, func: Callable) -> Monad[B]:
#     #    """Map function over monadic value.
#     #
#     #    Takes a function and a monadic value and maps the function over the
#     #    monadic value
#     #
#     #    Haskell: liftM :: (Monad m) => (a -> b) -> m a -> m b
#     #
#     #    This is really the same function as Functor.fmap, but is instead
#     #    implemented using bind, and does not rely on us inheriting from
#     #    Functor.
#     #    """
#     #
#     #    return self.bind(lambda x: Monad.unit(func(x)))
# 
# 
#     #def join(self):
#     #    """join :: Monad m => m (m a) -> m a
#     #
#     #    The join function is the conventional monad join operator. It is
#     #    used to remove one level of monadic structure, projecting its
#     #    bound argument into the outer level."""
# 
#     #    return self.bind(identity)
# 
# Path: oslash/typing/monoid.py
# class Monoid(Protocol[TSource]):
#     """The Monoid abstract base class.
# 
#     The class of monoids (types with an associative binary operation that
#     has an identity). Instances should satisfy the following laws:
# 
#     mappend mempty x = x
#     mappend x mempty = x
#     mappend x (mappend y z) = mappend (mappend x y) z
#     mconcat = foldr mappend mempty
#     """
# 
#     @classmethod
#     @abstractmethod
#     def empty(cls) -> 'Monoid[TSource]':
#         """Create empty monoid.
# 
#         Haskell: mempty :: m
# 
#         The empty element and identity of append.
#         """
# 
#         raise NotImplementedError
# 
#     def __add__(self, other):
#         """Append other monoid to this monoid.
# 
#         Haskell: mappend :: m -> m -> m
# 
#         An associative operation
#         """
#         raise NotImplementedError


# Path: oslash/writer.py
from typing import Callable, Tuple, Any, TypeVar, Generic, Union, cast
from .typing import Functor
from .typing import Monad
from .typing import Monoid


    @classmethod
    def unit(cls, value: TSource) -> 'Writer[TSource, TLog]':
        """Wrap a single value in a Writer.

        Use the factory method to create *Writer classes that
        uses a different monoid than str, or use the constructor
        directly.
        """
        return Writer(value, log=cast(TLog, ""))

    def run(self) -> Tuple[TSource, TLog]:
        """Extract value from Writer.

        This is the inverse function of the constructor and converts the
        Writer to s simple tuple.
        """
        return self._value

    @staticmethod
    def apply_log(a: tuple, func: Callable[[Any], Tuple[TSource, TLog]]) -> Tuple[TSource, TLog]:
        """Apply a function to a value with a log.

        Helper function to apply a function to a value with a log tuple.
        """
        value, log = a
        new, entry = func(value)
        return new, log + entry

    @classmethod

    def create(cls, class_name: str, monoid_type=Union[Monoid, str]):