Regarding static typing and dynamic typing, Practical Foundation of Programming Languages by Harper says:
There have been many attempts by advocates of dynamic typing to distinguish dynamic from static languages. It is useful to consider the supposed distinctions from the present viewpoint.
Dynamic languages associate types with values, whereas static languages associate types to variables. Dynamic languages associate classes, not types, to values by tagging them with identiﬁers such as num and fun. This form of classiﬁcation amounts to a use of recursive sum types within a statically typed language, and hence cannot be seen as a distinguishing feature of dynamic languages. Moreover, static languages assign types to expressions, not just variables. Because dynamic languages are just particular static languages (with a single type), the same can be said of dynamic languages.
Dynamic languages check types at run-time, whereas static language check types at compile time. Dynamic languages are just as surely statically typed as static languages, albeit for a degenerate type system with only one type. As we have seen, dynamic languages do perform class checks at run-time, but so too do static languages that admit sum types. The difference is only the extent to which we must use classiﬁcation: always in a dynamic language, only as necessary in a static language.
Dynamic languages support heterogeneous collections, whereas static languages sup- port homogeneous collections. The purpose of sum types is to support heterogeneity, so that any static language with sums admits heterogeneous data structures. A typical example is a list such as
cons(num; cons(fun(x.x); nil))
(written in abstract syntax for emphasis). It is sometimes said that such a list is not representable in a static language, because of the disparate nature of its components. Whether in a static or a dynamic language, lists are type homogeneous, but can be class heterogeneous. All elements of the above list are of type dyn; the ﬁrst is of class num, and the second is of class fun.
Thus, the seeming opposition between static and dynamic typing is an illusion. The question is not whether to have static typing, but rather how best to embrace it. Conﬁning one’s attention to a single recursive type seems pointlessly restrictive. Indeed, many so- called untyped languages have implicit concessions to there being more than one type. The classic example is the ubiquitous concept of “multi-argument functions,” which are a concession to the existence of products of the type of values (with pattern matching). It is then a short path to considering “multi-result functions,” and other ad hoc language features that amount to admitting a richer and richer static type discipline.
So "dynamic languages are just particular static languages (with a single type)". What is the single type in a dynamic language?
For example, Python is said to use the reference model of variables, as opposed to the value model of variables. References are not explicit.
Is it because of references that a list in Python can have elements of different "types", i.e. achieving heterogeneous collections in the quote?
Is the "single type" in Python the type for all the references? Is it the same for other dynamic typing languages, i.e. is the "single type" in a dynamic typing language the type for all the references? Or is reference just an implementation option of the single type in a dynamic language, and there might be other implementation options?
Do references which refer to values of different "types" have the same type?