88 lines
2.4 KiB
Python
88 lines
2.4 KiB
Python
""" The Continuation Monad
|
|
|
|
* https://wiki.haskell.org/MonadCont_under_the_hood
|
|
* http://blog.sigfpe.com/2008/12/mother-of-all-monads.html
|
|
* http://www.haskellforall.com/2012/12/the-continuation-monad.html
|
|
|
|
"""
|
|
|
|
from typing import Callable, Generic, TypeVar
|
|
|
|
|
|
from .util import identity, compose
|
|
from .typing import Monad, Functor
|
|
|
|
T = TypeVar('T')
|
|
T2 = TypeVar('T2')
|
|
TResult = TypeVar('TResult')
|
|
|
|
TCont = Callable[[T], TResult]
|
|
|
|
|
|
class Cont(Generic[T, TResult]):
|
|
"""The Continuation Monad.
|
|
|
|
The Continuation monad represents suspended computations in continuation-
|
|
passing style (CPS).
|
|
"""
|
|
|
|
def __init__(self, comp: Callable[[TCont], TResult]) -> None:
|
|
"""Cont constructor.
|
|
|
|
Keyword arguments:
|
|
cont -- A callable
|
|
"""
|
|
self._comp = comp
|
|
|
|
@classmethod
|
|
def unit(cls, value: T) -> 'Cont[T, TResult]':
|
|
"""Create new continuation.
|
|
|
|
Haskell: a -> Cont a
|
|
"""
|
|
fn: Callable[[TCont], TResult] = lambda cont: cont(value)
|
|
return Cont(fn)
|
|
|
|
def map(self, fn: Callable[[T], T2]) -> 'Cont[T2, TResult]':
|
|
r"""Map a function over a continuation.
|
|
|
|
Haskell: fmap f m = Cont $ \c -> runCont m (c . f)
|
|
"""
|
|
def comp(cont: Callable[[T2], TResult]) -> TResult:
|
|
return self.run(compose(cont, fn))
|
|
return Cont(comp)
|
|
|
|
def bind(self, fn: Callable[[T], 'Cont[T2, TResult]']) -> 'Cont[T2, TResult]':
|
|
r"""Chain continuation passing functions.
|
|
|
|
Haskell: m >>= k = Cont $ \c -> runCont m $ \a -> runCont (k a) c
|
|
"""
|
|
return Cont(lambda cont: self.run(lambda a: fn(a).run(cont)))
|
|
|
|
@staticmethod
|
|
def call_cc(fn: Callable) -> 'Cont':
|
|
r"""call-with-current-continuation.
|
|
|
|
Haskell: callCC f = Cont $ \c -> runCont (f (\a -> Cont $ \_ -> c a )) c
|
|
"""
|
|
return Cont(lambda c: fn(lambda a: Cont(lambda _: c(a))).run(c))
|
|
|
|
def run(self, cont: Callable[[T], TResult]) -> TResult:
|
|
return self._comp(cont)
|
|
|
|
def __or__(self, func):
|
|
"""Use | as operator for bind.
|
|
|
|
Provide the | operator instead of the Haskell >>= operator
|
|
"""
|
|
return self.bind(func)
|
|
|
|
def __call__(self, comp: Callable[[T], TResult]) -> TResult:
|
|
return self.run(comp)
|
|
|
|
def __eq__(self, other) -> bool:
|
|
return self(identity) == other(identity)
|
|
|
|
|
|
assert isinstance(Cont, Functor)
|
|
assert isinstance(Cont, Monad)
|