In Python variables already can have multiple instances (not simultaneously of course).
>>> x = 5
>>> type(x)
<type 'int'>
>>> x = ["you", "me", "them"]
>>> type(x)
<type 'list'>
For example in your code you can do:
def f(x):
if isinstance(x, int):
pass
elif isinstance(x, float):
pass
else:
raise TypeError
If you want to stay closer to Haskell you can do something like this. Say in Haskell you have
data Item = Person String Int String | Car String Bool
In Python 3.6 you write
def g(x):
tag, *values = x
if tag == 'Person':
name, age, e_mail_address = values
# do something
pass
elif tag == 'Car':
brand, is_diesel = values
# do something
pass
else:
raise TypeError
In Haskell it is also called 'sum types'.
An alternative is to use classes. Makes more explicit what is going on. For example Haskell's Either
is
data Either a b = Left a | Right b
In Python Either Int Float
it will be something like
class Either:
def __init__(self, a=None, b=None):
if (a is None) and (b is not None):
self._left = None
self._right = float(b)
elif (a is not None) and (b is None):
self._left = int(a)
self._right = None
else:
raise TypeError
@property
def is_left(self):
return self._left is not None
@property
def is_right(self):
return self._right is not None
@property
def value(self):
if self.is_left:
return self._left
elif self.is_right:
return self._right
def __eq__(self, other):
if isinstance(other, Either):
if self.is_left == other.is_left:
return self.value == other.value
else:
return False
else:
raise TypeError
def __str__(self):
return str(self.value)