Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can Python implement dependent types?

Tags:

A simple demo of dependent types in Idris is Vector, whose type depends on its value.

We can use type hints in Python:

from typing import List

def append(a: List[int], b: List[int]) -> List[int]:
    return a + b

print(append([1, 2], [1, 3, 4]))

So, can we implement a type Vect, which can be used as in

def append(a: Vect[m, T], b: Vect[n, T]) -> Vect[(m+n), T]:
    return a + b

, where m and n are natural numbers, and T is any type?

like image 660
xiang Avatar asked Apr 08 '17 09:04

xiang


People also ask

What is dependent type programming in Python?

What is dependent typing? It is a concept when you rely on values of some types, not just raw types. Consider this example: from typing import Union def return_int_or_str(flag: bool) -> Union[str, int]: if flag: return 'I am a string!' return 0.

What is dependent type programming?

In computer science and logic, a dependent type is a type whose definition depends on a value. It is an overlapping feature of type theory and type systems. In intuitionistic type theory, dependent types are used to encode logic's quantifiers like "for all" and "there exists".

Are dependent types useful?

Dependent types are incredibly useful for 'real programming', and a natural extension of type systems we use on a regular basis, and I seek to explain why.


1 Answers

Yes, but it's super hacky (and it would be really hard to get everything right). First, you would need to modify the object's type when a change is made to the object.

From the docs:

"An object’s type determines the operations that the object supports (e.g., “does it have a length?”) and also defines the possible values for objects of that type. The type() function returns an object’s type (which is an object itself). Like its identity, an object’s type is also unchangeable. [1]"

But in the footnote for [1]:

"[1] It is possible in some cases to change an object’s type, under certain controlled conditions. It generally isn’t a good idea though, since it can lead to some very strange behaviour if it is handled incorrectly."

To change an object's type, you need to set the object's __class__ attribute to a different class. Here's a simple example with two value-dependent types of integers:

class Integer:                                                                           
    def __init__(self, value):                                                           
        self.value = int(value)                                                          
        self.set_class()                                                                 

    def set_class(self):                                                                 
        if self.value < 10:                                                              
            self.__class__ = LessThanTen                                                 
        else:                                                                            
            self.__class__ = TenOrMore                                                   

    def add(self, value):                                                                
        self.value += int(value)                                                         
        self.set_class()                                                                 

class TenOrMore(Integer):                                                                
    def __init__(self):                                                                  
        pass                                                                             
        raise ValueError("Use Integer()")                                                

class LessThanTen(Integer):                                                              
    def __init__(self):                                                                  
        raise ValueError("Use Integer()")

You can then do standard operations on them and have them change according to their new value:

>>> from dependent import Integer, TenOrMore, LessThanTen
>>> a = Integer(5)
>>> print(a.value, type(a))
5 <class 'dependent.LessThanTen'>
>>> a.add(10)
>>> print(a.value, type(a))
15 <class 'dependent.TenOrMore'>

This approach requires hard-coding classes in advance. It would be possible to generate classes dynamically, though it would require some generating gymnastics to ensure everything lived in the same scope (such as a top-level dictionary and class generator function). However, I don't think the current type hinting system would support such dynamically-generated classes.

like image 154
David Slater Avatar answered Oct 14 '22 21:10

David Slater