Skip to content

Instantly share code, notes, and snippets.

@luther9
Created November 18, 2021 17:42
Show Gist options
  • Save luther9/b55d0f988a8da2c8728a9534cd3acb74 to your computer and use it in GitHub Desktop.
Save luther9/b55d0f988a8da2c8728a9534cd3acb74 to your computer and use it in GitHub Desktop.
IO monad in Python
from collections.abc import Callable
from dataclasses import dataclass
import traceback
@dataclass(frozen=True)
class IO:
_action: Callable
allowedExceptions: tuple = ()
@classmethod
def unit(cls, x):
return cls(lambda: x)
@classmethod
def wrap(cls, f, allowedExceptions=()):
return lambda *args, **kwargs: cls(
lambda: f(*args, **kwargs),
allowedExceptions,
)
def __call__(self):
try:
return self._action()
except self.allowedExceptions as e:
return e
def bind(self, f):
return IO(lambda: f(self())())
def seq(self, other):
"""Equivalent to self.bind(lambda x: other)."""
@IO
def action():
self()
return other()
return action
IO.done = IO.unit(None)
ioInput = IO(input, EOFError)
ioPrint = IO.wrap(print)
def echoLoop(s):
return IO.done if isinstance(s, EOFError) else ioPrint(s).seq(echo)
echo = ioInput.bind(echoLoop)
echo()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment