This repository has been archived by the owner on Oct 4, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 14
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 |
jspahrsummers
added
mypy
Relating to the ADT mypy plugin
question
Further information is requested
labels
Aug 2, 2020
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') |
Sign up for free
to subscribe to this conversation on GitHub.
Already have an account?
Sign in.
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: