With the current typing implementation, how far can we make this work as expected?
Is there any innate problem in this approach?
The problematic point is the method of generic protocol, taking an instance of self, where the type variable could be different from self.
from __future__ import annotations
from typing import Any, Callable, Generic, Protocol, TypeVar
from dataclasses import dataclass
A = TypeVar("A")
B = TypeVar("B")
class Functor(Protocol[A]):
@staticmethod
def fmap(f: Callable[[A], B], x: Functor[A]) -> Functor[B]: ...
class Applicative(Functor[A], Protocol[A]):
@staticmethod
def pure(x: Any) -> Applicative[A]: ...
@staticmethod
def ap(f: Applicative[Callable[[A], B]], x: Applicative[A]) -> Applicative[B]: ...
class Monad(Applicative[A], Protocol[A]):
@staticmethod
def bind(x: Monad[A], f: Callable[[A], Monad[B]]) -> Monad[B]: ...
@dataclass
class Io(Generic[A]):
action: Callable[[], A]
@staticmethod
def fmap(f: Callable[[A], B], x: Io[A]) -> Io[B]:
return Io(lambda: f(x.action()))
@staticmethod
def pure(x: A) -> Io[A]:
return Io(lambda: x)
@staticmethod
def ap(f: Io[Callable[[A], B]], x: Io[A]) -> Io[B]:
return Io(lambda: f.action()(x.action()))
@staticmethod
def bind(x: Io[A], f: Callable[[A], Io[B]]) -> Io[B]:
return Io(lambda: f(x.action()).action())
def taking_monad(x: Monad[int]) -> bool:
return True
taking_monad(Io(lambda: 1))
This results error like this .
Argument 1 to "taking_monad" has incompatible type "Io[int]"; expected "Monad[int]"Mypy[arg-type](https://mypy.readthedocs.io/en/latest/_refs.html#code-arg-type)
Following member(s) of "Io[int]" have conflicts:
Expected:
def [B] ap(f: Applicative[Callable[[int], B]], x: Applicative[int]) -> Applicative[B]
Got:
def [B] ap(f: Io[Callable[[int], B]], x: Io[int]) -> Io[B]
Expected:
def [B] bind(x: Monad[int], f: Callable[[int], Monad[B]]) -> Monad[B]
Got:
def [B] bind(x: Io[int], f: Callable[[int], Io[B]]) -> Io[B]
<2 more conflict(s) not shown>Mypy
Argument 1 to "taking_monad" has incompatible type "Io[int]"; expected "Monad[int]"Mypy[arg-type](https://mypy.readthedocs.io/en/latest/_refs.html#code-arg-type)
Following member(s) of "Io[int]" have conflicts:
The same question is also on the discussion of python/typing