# 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/util/basic.py
# def indent(level, size=2):


from abc import abstractmethod
from typing import Any, Callable, Generic, TypeVar, Tuple
from .typing import Functor
from .typing import Monad
from .util import indent as ind, Unit

    def __init__(self, fn: Callable[[str], IO[TSource]]) -> None:
        self._fn = fn

    def bind(self, func: Callable[[TSource], IO[TResult]]) -> IO[TResult]:
        """IO a -> (a -> IO b) -> IO b"""

        g = self._fn
        return Get(lambda text: g(text).bind(func))

    def map(self, func: Callable[[TSource], TResult]) -> IO[TResult]:
        # Get (\s -> fmap f (g s))
        g = self._fn
        return Get(lambda s: g(s).map(func))

    def run(self, world: int) -> TSource:
        """Run IO Action"""

        func = self._fn
        new_world, text = pure_input(world)
        action = func(text)
        return action(world=new_world)

    def __call__(self, world: int = 0) -> TSource:
        return self.run(world)

    def __str__(self, m: int = 0, n: int = 0) -> str:
        g = self._fn
        i = "x%s" % n
        a = g(i).__str__(m + 1, n + 1)

# 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/util/basic.py
# def indent(level, size=2):


# Path: oslash/ioaction.py
from abc import abstractmethod
from typing import Any, Callable, Generic, TypeVar, Tuple
from .typing import Functor
from .typing import Monad
from .util import indent as ind, Unit


    def __init__(self, fn: Callable[[str], IO[TSource]]) -> None:
        self._fn = fn

    def bind(self, func: Callable[[TSource], IO[TResult]]) -> IO[TResult]:
        """IO a -> (a -> IO b) -> IO b"""

        g = self._fn
        return Get(lambda text: g(text).bind(func))

    def map(self, func: Callable[[TSource], TResult]) -> IO[TResult]:
        # Get (\s -> fmap f (g s))
        g = self._fn
        return Get(lambda s: g(s).map(func))

    def run(self, world: int) -> TSource:
        """Run IO Action"""

        func = self._fn
        new_world, text = pure_input(world)
        action = func(text)
        return action(world=new_world)

    def __call__(self, world: int = 0) -> TSource:
        return self.run(world)

    def __str__(self, m: int = 0, n: int = 0) -> str:
        g = self._fn
        i = "x%s" % n
        a = g(i).__str__(m + 1, n + 1)

        return "%sGet (%s => \n%s\n%s)" % (ind(m), i, a, ind(m))