What is the difference, at various stages of the read-compile-run pipeline, between a type
declaration and a newtype
declaration?
My assumption was that they compiled down to the same machine instructions, and that the only difference was when the program is typechecked, where for example
type Name = String
newtype Name_ = N String
You can use a Name
anywhere a String
is required, but the typechecker will call you out if you use a Name_
where a String
is expected, even though they encode the same information.
I'm asking the question because, if this is the case, I don't see any reason why the following declarations shouldn't be valid:
type List a = Either () (a, List a)
newtype List_ a = L (Either () (a, List_ a))
However, the type checker accepts the second one but rejects the first. Why is that?
Luqui's comment should be an answer. Type synonym's in Haskell are to first approximation nothing more than macros. That is, they are expanded by the type checker into fully evaluated types. The type checker can not handle infinite types, so Haskell does not have equi-recursive types.
newtypes
provide you iso-recursive types that, in GHC, essentially compile down to equi-recursive types in the core language. Haskell is not GHC core, so you don't have access to such types. Equi-recursive types are just a bit harder to work with both for type checkers and humans, while iso-recursive types have equivalent power.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With