Closed as not planned
Description
As mypy understands isinstance
checks, I wondered if I can use this to mimic GADT (Generalized algebraic data type) in functional languages such as Haskell and OCaml.
I tried to mimic following Haskell code
data Expr a where
Const :: a -> Expr a
Add :: Expr Int -> Expr Int -> Expr Int
eval :: Expr a -> a
eval (Const x) = x
eval (Add a b) = eval a + eval b
with the following Python code:
import abc
from typing import Generic, TypeVar
A = TypeVar('A')
class Expr(Generic[A], metaclass=abc.ABCMeta):
pass
class Const(Expr[A]):
value: A
def __init__(self, value: A):
self.value = value
class Add(Expr[int]):
left: Expr[int]
right: Expr[int]
def __init__(self, left: Expr[int], right: Expr[int]):
self.left = left
self.right = right
def eval(e: Expr[A]) -> A:
if isinstance(e, Const):
# reveal_type(e) # => Const[Any]
return e.value
elif isinstance(e, Add):
# reveal_type(e) # => <nothing>
return eval(e.left) + eval(e.right)
# error: <nothing> has no attribute "left"
# error: <nothing> has no attribute "right"
else:
assert False
example = Add(Const[int](2), Const[int](1))
print(eval(example))
But in the elif isinstance(e, Add)
branch the type of e
is inferred as '<nothing>'
causing type errors.
As '<nothing>'
is not documented (c.f. #3030), I'm not sure if this is intended behavior. So I report it here just in case, though the attempt is just out of curiosity.