Haskell has structured types, but not structural typing, and that's not likely to change.*
The refusal to permit nominally different but structurally similar types as interchangeable arguments is called type safety. It's a good thing. Haskell even has a newtype declaration to provide types which are only nominally different, to allow you to enforce more type safety. Type safety is an easy way to catch bugs early rather than permit them at runtime.
In addition to amindfv's good answer which includes ad hoc polymorphism via typeclasses (effectively a programmer-declared feature equivalence), there's parametric polymorphism where you allow absolutely any type, so [a]
allows any type in your list and BTree a
allows any type in your binary tree.
This gives three answers to "are these types interchangeable?".
- No; the programmer didn't say so.
- Equivalent for a specific purpose because the programmer said so.
- Don't care - I can do the same thing to this collection of data because it doesn't use any property of the data itself.
There's no 4: compiler overrules programmer because they happened to use a couple of Ints and a String like in that other function.
*I said Haskell is unlikely to change to structural typing. There is some discussion to introduce some form of extensible records, but no plans to make (Int,(Int,Int))
count as the same as (Int, Int, Int)
or Triple {one::Int, two::Int, three::Int}
the same as Triple2 {one2::Int, two2::Int, three2::Int}
.