I want to implement in python 3.8 a Liste class the Lisp way with head and tail, car(), cdr() and nil. I want to define a generic type accepting objects of Type T in the Liste.
from __future__ import annotations
from typing import TypeVar, Callable, Generic
T = TypeVar('T')
class Liste(Generic[T]):
def __init__(self, h: T, t: Liste[T]) -> None:
self.head = h
self.tail = t
@staticmethod
def nil() -> Liste[T]:
return Liste(None, None)
def est_vide(self) -> bool:
return (self.head is None) and (self.tail is None)
def cdr(self)->Liste[T]:
if self.tail is None: return Liste.nil()
else: return self.tail
def sum(self)->T:
if self.est_vide():
return 0
else:
return self.head + self.cdr().sum()
I had a very good moment with type hints all along. But mypy points 4 errors
liste_sof.py:13: error: Argument 1 to "Liste" has incompatible type "None"; expected "T"
liste_sof.py:13: error: Argument 2 to "Liste" has incompatible type "None"; expected "Liste[T]"
liste_sof.py:23: error: Incompatible return value type (got "int", expected "T")
liste_sof.py:25: error: Unsupported left operand type for + ("T")
Found 4 errors in 1 file (checked 1 source file)
Problem 1 is to be able to specify that I expect T objects that implement the __add__ method. I don't know how to do that.
Problem 2 is to deal with the special Liste.nil() empty object of my class.
Mypy is complaining because you need to use
Optionalif you wanthortto be able to beNone, otherwise, you are implying everything must beNone, which isn't generic.You can use structural typing with a
Protocolto express "has__add__".Finally, there is no clean way to get "the empty object". For built-in types,
type(self)()may work, but honestly, I would just force the API take the initial value.As I stated in the comments, this class is very academic, you probably shouldn't actually use it. It will be inefficient. At the very least, you shouldn't use recursion for
sum.