For most of my life, I equated types with sets of values, but after learning Haskell and working with higher-kinded types, type classes, and existential types, I realized I don't know anymore what a type _is_. I know that type systems provide proof that certain classes of operations are impossible (like comparing a number to a string, or dereferencing an invalid reference).
It's pretty mindbending to use existentials or GADTs and pull two values of a record and not know anything about those values except that, for example, they can be compared for equality.
data HasTwoEq = forall a. Eq a => HasTwoEq a a
equalOrNot :: HasTwoEq -> Bool
equalOrNot (HasTwoEq x y) = x == y
The example is contrived, but it illustrates the point that the types of x and y are not known, _except_ that they can be compared.That's not the kind of thing you can express with, say, Java or Go interfaces, but it makes perfect sense once you start to break down the mental walls you've built in your head over the years.
I'm thrilled to see a growing body of accessible* PL and type theory literature, because these things are important to helping us develop software at increasingly large scales, and it's clear that very few people -- including myself! -- know enough about this topic.
* e.g. https://cs.brown.edu/~sk/Publications/Books/ProgLangs/2007-0...
I tried to do my part here: http://chadaustin.me/2015/07/sum-types/ and http://chadaustin.me/2015/09/haskell-is-not-a-purely-functio...