`Mappable` provides short-term comfort due to familiarity, but to do so it sacrifices precision that is essential in the long term.
1) For all sets s, s.map(identity) == s ==> true
2) For all sets s, functions f and g, s.map(x => f(g(x)) == s.map(g).map(f) ==> true
On the other hand, Map's map method is much more horrible, and does violate the 2nd functor law where f == g == _.swap :
Map(1 -> 2, 2 -> 2).map(_.swap).map(_.swap) ==> Map(2 -> 2)
Map(1 -> 2, 2 -> 2).map(_.swap.swap) ==> Map(1 -> 2, 2 -> 2)
Further, it behaves differently depending on if it is known to be a Map at compile-time, or if it is only known to be an Iterable[(K, V)], due to overloading:
Map(1 -> 2, 2 -> 2).map(_.swap) ==> Map(2 -> 2)
(Map(1 -> 2, 2 -> 2): Iterable[(Int, Int)]).map(_.swap) ==> List(2 -> 1, 2 -> 2)
Definitions are precise, not names. Names aren't what makes math work, it's the precise definitions, inference rules and theorems, regardless of the language in which they are written. 'printf' does not work the same in all programming language yet everyone knows what that name means.