
Dear Cafe - I wanted a quick example (for teaching) that shows a difference between data and newtype. You'd think that `newtype` makes things more strict, so we'd see more exceptions. Then try the following, and try to guess the semantics beforehand: ghci> data D = D Bool ghci> case D undefined of D x -> () ghci> case undefined of D x -> () ghci> newtype N = N Bool ghci> case N undefined of N x -> () ghci> case undefined of N x -> () What examples do you use? I'm interested both in simple ones, and confusing/obfuscated ones. Yes I know I can ghci> seq (D undefined) () () ghci> seq (N undefined) () *** Exception: Prelude.undefined but that `seq` is extra magic that needs to be explained. Well, perhaps I should. To show that I've done some homework here: the primary source of truth is the Haskell Language Report (well hidden at the bottomest end of https://www.haskell.org/documentation/) and it uses (in 4.2.3 Datatype Renamings) the concept of "equivalent to bottom". Then 6.2 Strict Evaluation shows how to test that with `seq` (without mentioning newtype, and that's fine since the Report is not a tutorial). This suggests that `seq` is really the way to go here. There are examples for data/newtype/case combined in 3.17.2 Informal Semantics of Pattern Matching but they distinguish between newtype N = N Bool and data D = D !Bool (with a bang). - J.W.