-
Notifications
You must be signed in to change notification settings - Fork 14
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Function "bind" on Result adt doesn't typecheck #40
Comments
I haven't had a chance to try this sample out myself, but my guess is that the typechecker is failing to unify the types of |
I revealed the type for the from adt import adt, Case
from typing import Callable, Generic, TypeVar
A = TypeVar("A")
B = TypeVar("B")
E = TypeVar("E")
@adt
class Result(Generic[E, A]):
OK: Case[A]
ERR: Case[E]
def bind(self, f: Callable[[A], Result[E, B]]) -> Result[E, B]:
ok: Callable[[A], Result[E, B]] = f
err: Callable[[E], Result[E, B]] = Result.ERR
return self.match(ok=f, err=err) |
Does it work if you try to write something like this without the |
The following program type-checks with mypy 0.782 and python 3.8.5: from dataclasses import dataclass
from typing import Generic, TypeVar, Callable, cast, Union, Mapping
E = TypeVar("E")
A = TypeVar("A")
B = TypeVar("B")
Fun = Callable[[A], B]
class Result(Generic[E, A]):
@staticmethod
def OK(value: A) -> 'Result[E, A]':
return Result(True, value)
@staticmethod
def ERR(value: E) -> 'Result[E, A]':
return Result(False, value)
def __init__(self, ok: bool, value: Union[E, A]):
self.ok = ok
self.value = value
def __repr__(self):
return f"OK {repr(self.value)}" if self.ok else f"ERR {repr(self.value)}"
def __str__(self):
return repr(self)
def match(self, ok: Fun[A, B], err: Fun[E, B]) -> B:
return ok(cast(A, self.value)) if self.ok else err(cast(E, self.value))
def bind(self, f: Fun[A, 'Result[E, B]']) -> 'Result[E, B]':
return self.match(ok=f, err=Result.ERR)
@dataclass
class User:
id: int
name: str
USERS: Mapping[int, User] = {
0: User(id=0, name="root")
}
def parse_user_id(s: str) -> Result[str, int]:
try:
return Result.OK(int(s))
except ValueError as e:
return Result.ERR(e.args[0])
def get_user(id: int) -> Result[str, User]:
if id not in USERS:
return Result.ERR('User not found')
else:
return Result.OK(USERS[id])
def get_user_from_str(s: str) -> Result[str, User]:
return parse_user_id(s).bind(get_user)
print(get_user_from_str("foo")) # ERR "invalid literal for int() with base 10: 'foo'"
print(get_user_from_str("10")) # ERR 'User not found'
print(get_user_from_str("0")) # OK User(id=0, name='root') |
The following adt with an extra method
bind
is failing to typecheck. Mypy is returningIf I reveal the type of the match function, mypy says:
and revealing the ok value:
So, the revealed types seems to be correct, but mypy still reports an error.
The text was updated successfully, but these errors were encountered: