This is a dumb question that’s been bugging me for a bit. Why can’t I write a newtype with multiple parameters,
newtype A = A Int Int
while the tuple version is just fine?
newtype A = A (Int, Int)
the former is much nicer in things like pattern matching.
newtype A = A Intcreates a type isomorphic toInt. That is, it behaves exactly likeIntw.r.t. e.g.bottom, but under a different name.This is in contrast with
data A = A Intwhich creates a lifted type that behaves differently from Int. There’s another value added that is not inInt:A undefined(which is distinct fromundefined::A).Now,
newtype A = A (Int, Int)creates a type isomorphic to(Int, Int). Which is, incidentally, exactly exactly whatdata A = A Int Intdoes.So if we admit
newtype A = A Int Intas being equivalent tonewtype A = A (Int, Int), what do we have?newtype A = A Int Intis equivalent tonewtype A = A (Int, Int)which is equivalent todata A = A Int Int.newtype A = A Int Intis equivalent todata A = A Int Int(sonewtypeis redundant in this case), butnewtype A = A Intis not equivalent todata A = A Int(which is the whole point of havingnewtypein the first place).So we must conclude that
newtype A = A Int Intbeing equivalent tonewtype A = A (Int, Int)creates redundancy and inconsistency, and we’re better off not allowing it.There’s probably no way to give
newtype A = A Int Intsome other meaning which is free from these inconsistencies (or else it would be found and used I suppose 😉