I\'m struggling to understand why these two snippets produce different results under the so-called \"poor man\'s strictness analysis\".
The first example uses data
As you probably know, the main difference between data
and newtype
is that with data
the data constructors are lazy while with newtype
the data constructors are strict, i.e. given the following types
data D a = D a
newtype N a = N a
then D ⊥ `seq` x = x
, but N ⊥ `seq` x = ⊥
.(where ⊥
stands for "bottom", i.e. undefined value or error)
What is perhaps less commonly known, however, is that when you pattern match on these data constructors, the roles are "reversed", i.e. with
constD x (D y) = x
constN x (N y) = x
then constD x ⊥ = ⊥
(strict), but constN x ⊥ = x
(lazy).
This is what's happening in your example.
Parser f <*> Parser x = Parser h where ...
With data
, the pattern match in the definition of <*>
will diverge immediately if either
of the arguments are ⊥
, but with newtype
the constructors are ignored and it is
just as if you'd written
f <*> x = h where
which will only diverge for x = ⊥
if x
is demanded.