|
|
Line 1: |
Line 1: |
| newtype is not exactly like data. #haskell is frequently being questioned about the difference.
| | #REDIRECT [[Newtype]] |
| | |
| Firstly, as mentioned in most tutorials, newtype can handle only a single data constructor, and a single field in that single data constructor.
| |
| | |
| Secondly, newtype is strict on its field.
| |
| | |
| So how is:
| |
| | |
| <code>newtype NewType = NewType Int</code>
| |
| | |
| different from:
| |
| | |
| <code>data NewData = NewData Int</code>
| |
| | |
| The number of bottoms differ. Since data is lazy, it introduces a new bottom in addition to the bottom that existed in the Int itself.
| |
| | |
| NewData can be _|_ or it can be (NewData _|_). NewType cannot be _|_ but can only be (NewType _|_).
| |
| | |
| So, lets try another comparison:
| |
| | |
| How is:
| |
| | |
| <code>newtype NewType = NewType Int</code>
| |
| | |
| different from:
| |
| | |
| <code>data NewData = NewData !Int</code>
| |
| | |
| Here, the number of bottoms is the same, but they are not quite the same bottoms. NewType's bottom is: (NewType _|_) (the bottom is <b>inside</b> the pattern), whereas NewData's bottom is (_|_) (the bottom is the <b>whole</b> pattern).
| |
| | |
| To demonstrate this difference, we can use the following code;
| |
| <code>
| |
| case (NewType undefined) of
| |
| (NewType _) -> "Happy happy joy joy :-)"
| |
| case (NewData undefined) of
| |
| (DataType _) -> "Won't ever get here :-("
| |
| </code>
| |
| | |
| Since the newtype bottom is inside the pattern, and we catch that with (_) and never use it, we don't actually hit the bottom. But the NewData bottom is on the whole pattern, so even matching the single data constructor that way is a bottom.
| |