To: malcolm
From: colin
Date: Thu, 16 Mar 2000 13:20:28 +0000
Subject: GEM's bug reports

Here's five different applications of cut.  hbc and hugs can work out
versions 2--5 but (understandably) for version 1, hbc detects a black
hole and hugs' control stack overflows.

nhc13 (/grp/haskell/bin/nhc13) diverges (presumably as it doesn't stop
or run out of heap space in the large amount of time I let it run) on
versions 1--4 but works on version 5.

-------------------------------------------------------------------------------
import System(getArgs)

cut :: [a] -> [Int] -> [[a]]
cut = cut' 0
cut' 0 xs [] = [xs]
cut' 0 xs (p:ps) = xs : cut' p xs ps
cut' p (x:xs) ps = cut' (p-1) xs ps

ints :: [Int]
ints = iterate (+ 1) 10

eg1 :: Int
eg1 = head ns3
   where ((n1:_):ns2:ns3:_) = cut ints [1,n1]

eg2 :: Int
eg2 = head ns3
   where ((n1:_):(~(ns2:ns3:_))) = cut ints [1,n1]

eg3 :: Int
eg3 = head ns3
   where ((~(n1:_)):(~(ns2:(~(ns3:_))))) = cut ints [1,n1]

eg4 :: Int
eg4 = head ns3
   where nss1 = cut ints [1,head ns1]
         (ns1:nss2) = nss1
         (ns2:nss3) = nss2
         (ns3:nss4) = nss3

eg5 :: Int
eg5 = head ns3
   where ns1 = ints
         ns2 = drop 1 ns1
         ns3 = drop (head ns1) ns2

main = do argv <- getArgs
          print (case read (argv!!0) of
                    1 -> eg1
                    2 -> eg2
                    3 -> eg3
                    4 -> eg4
                    5 -> eg5)
-------------------------------------------------------------------------------


Compiling:
-------------------------------------------------------------------------------
class Queue t where
   emptyQ :: t Int
newtype StrictNull a = StrictNull ()
instance Queue StrictNull where
   emptyQ = StrictNull ()

data Queue t => Test t = Test (t Int)

eg = newNode `seq` True
   where newNode = Test 0

main = print eg
-------------------------------------------------------------------------------

produces the following error:

/grp/haskell/nhc13/lib_b/IRIX/nhc13comp: Error: Internal: CtxsSimplify expanded the type synonym (187 39) to (187 39)
Internal: expected a type constructor

===================

Ok, here's a program that prints

(False, True)

when it should print

(True, True)

There is no significance in the pair.  The only reason I included it
is to show that it's the presence of "(t Int)" in the Test datatype
that causes the problem, as replacing it with Int to form Test2 now
restores the expected behaviour.

-=GEM=-

-------------------------------------------------------------------------------
class Queue t where
   emptyQ :: t Int
newtype StrictNull a = StrictNull ()
instance Queue StrictNull where
   emptyQ = StrictNull ()

data Queue t => Test t = Test (t Int) Int

eg = newNode `seq` True
   where newNode = Test (emptyQ::StrictNull Int) 0

data Test2 = Test2 Int Int

eg2 = newNode `seq` True
   where newNode = Test2 0 0

main = print (eg,eg2)
-------------------------------------------------------------------------------

Here's a program that nhc13 complains about:

-------------------------------------------------------------------------------
class Test q where
   test :: q a
   test3 :: q a -> Bool

--default Data

data Data a = Nil

instance Test Data where
   test = Nil
   test3 q = True

data T a = Single a | Other (T a)

f :: Test q => T a -> q a
f (Single a) = test
f (Other t) = test3 q `seq` q
   where q = f t

main = print True

--main = print (case (f (Other (Single True)) :: (Data Bool)) of Nil -> True)
-------------------------------------------------------------------------------

It complains with:

        Error after type deriving/checking:
No default for  Main.Test at 16:1.(218,[(158, 223)])

Hugs and hbc accept the code.  If I uncomment the "default Data" then
nhc13 also accepts the code.

There's a bizarre twist to this tale.  If we replace "newNode `seq`
True" in eg1 with "seq newNode $ True" it works.  If we replace it with
"seq newNode True" it does not work.

See the end of this message for the final problem program.

-=GEM=-

Ok, here's a program that prints

(False, True)

when it should print

(True, True)

There is no significance in the pair.  The only reason I included it
is to show that it's the presence of "(t Int)" in the Test datatype
that causes the problem, as replacing it with Int to form Test2 now
restores the expected behaviour.

- -=GEM=-

-------------------------------------------------------------------------------
class Queue t where
   emptyQ :: t Int
newtype StrictNull a = StrictNull ()
instance Queue StrictNull where
   emptyQ = StrictNull ()

data Queue t => Test t = Test (t Int) Int

eg = newNode `seq` True
   where newNode = Test (emptyQ::StrictNull Int) 0

data Test2 = Test2 Int Int

eg2 = newNode `seq` True
   where newNode = Test2 0 0

main = print (eg,eg2)
-------------------------------------------------------------------------------

-------------------------------------------------------------------------------
class Queue t where
   emptyQ :: t Int
newtype StrictNull a = StrictNull ()
instance Queue StrictNull where
   emptyQ = StrictNull ()

data Queue t => Test t = Test (t Int) Int

eg = newNode `seq` True
   where newNode = Test (emptyQ::StrictNull Int) 0

data Test2 = Test2 Int Int

eg2 = newNode `seq` True
   where newNode = Test2 0 0

eg3 = seq newNode $ True
   where newNode = Test (emptyQ::StrictNull Int) 0

main = print (eg,eg2,eg3)
-------------------------------------------------------------------------------

This program runs to print

(False,True,True)

Most bizarre!

================================
nhc13---strictness annotations

Another problem with nhc13.  The following program:

-------------------------------------------------------------------------------
import System(getArgs)

data Test = Test !Int

f :: Test -> Int -> Test
f (Test n) i = Test (n+i)

g :: Test -> Bool
g (Test _) = True

sfoldl :: Eval a => (a -> b -> a) -> a -> [b] -> a
sfoldl f z [] = z
sfoldl f z (x:xs) = sfoldl f fzx (fzx `seq` xs)
                  where fzx = f z x

main = do argv <- getArgs
          print (g (sfoldl f (Test 0) [1..(read (argv!!0))]))
-------------------------------------------------------------------------------

will explode in a small heap (eg. 40K) for large-ish values passed as
first argument (eg. 10000) under nhc13, with a profile confirming the
steep ramp of building (+) closures in the heap.  Under hbc, I can run
it on very large values (eg. 1000000) in a small heap (eg. 40K)
without the heap being overrun (I would do a heap profile, but
profiling is "a little broken" in hbc-0.9999.4 and I would have to
recompile the compiler to get this "broken" profiling).


-=GEM=-

