Add more sanity checking
[ghc-heap-view.git] / Demo.hs
diff --git a/Demo.hs b/Demo.hs
index 041eecd..2558984 100644 (file)
--- a/Demo.hs
+++ b/Demo.hs
@@ -17,43 +17,56 @@ main = do
     let x = l ++ l2 ++ args
     performGC
     putStrLn "ghc-heap-view-demo"
-    putStrLn "Here are a few different lists."
-    putStrLn $ "The first one, l, found at " ++ show (asBox l) ++ " is a module-level constant, and fully evaluated:"
-    getClosureData l >>= print
-    putStrLn $ "The second one, l2, found at " ++ show (asBox l2) ++ " is locally defined as l2 = 4:l. See how the cons-cell references l!"
-    getClosureData l2 >>= print
-    putStrLn $ "And here is the list args (" ++ show (asBox args) ++ ") that is static, but not known at compiletime, as it depends on the command line arguments:"
-    getClosureData args >>= print
-    putStrLn $ "And now we have, at " ++ show (asBox x) ++ ", the concatenation of them, but unevaluated. The thunk keeps a reference to l2 and args, but not l, as that is at a static address, unless you are running this in GHCi:"
-    getClosureData x >>= print
+    putStrLn ""
+    putStrLn "Here are a four different lists, where the first three are already evaluated."
+    putStrLn "The first one, l, was defined as a top level constant as "
+    putStrLn "> l = [1,2,3]"
+    putStrLn $ "and is now found at " ++ show (asBox l) ++ " (where the /2 is the pointer tag information) and fully evaluated:"
+    getClosureData l >>= printInd
+    putStrLn $ "The second one, l2, is locally defined"
+    putStrLn "> let l2 = 4:l" 
+    putStrLn $ "and now found at " ++ show (asBox l2) ++ ". See how the cons-cell references l!"
+    getClosureData l2 >>= printInd
+    putStrLn "And the binding"
+    putStrLn "> args <- map length `fmap` getArgs"
+    putStrLn $ "gives us at " ++ show (asBox args) ++ " a static, but at compile time unknown list:"
+    getClosureData args >>= printInd
+    putStrLn $ "And now we have, at " ++ show (asBox x) ++ ", the concatenation of them, but unevaluated:"
+    putStrLn "> let x = l ++ l2 ++ args"
+    putStrLn "The thunk keeps a reference to l2 and args, but not l, as that is at a static address, unless you are running this in GHCi:"
+    getClosureData x >>= printInd
 
     putStrLn ""
-    putStrLn "Now to some more closure types:"
+    putStrLn "Now to some more closure types. m and m' locally bound of type the unboxed type Int#, with values 42 resp. 23."
+    putStrLn "> let f = \\x n -> take (I# m + I# x) n ++ args"
+    putStrLn "      t = f m' l2"
     let !(I# m) = length args + 42
     let !(I# m') = length args + 23
     let f = \x n -> take (I# m + I# x) n ++ args
         t = f m' l2
-    putStrLn $ "The following value f (" ++ show (asBox f) ++ ") is a locally defined function that has args as a free variable, as well as an unboxed integer (42):"
-    getClosureData f >>= print
-    putStrLn "And the following is a thunk that applies f (also references here) to an unboxed value (23) and l2:"
-    getClosureData t >>= print
+    putStrLn $ "So here is (" ++ show (asBox f) ++ "), referencing its free variables args and 42:"
+    getClosureData f >>= printInd
+    putStrLn "And t is a thunk that applies f (also referenced here) to an unboxed value (23) and l2:"
+    getClosureData t >>= printInd
 
     putStrLn ""
-    putStrLn "Here is the standard example for self reference:"
+    putStrLn "Lastly, here is the standard example for self reference:"
     putStrLn "> let x = id (:) () x"
     let x = id (:) () x
     putStrLn $ "This is what x (" ++ show (asBox x) ++ ") looks like, at least without -O:"
-    getClosureData x >>= print
+    getClosureData x >>= printInd
     x `seq` return ()
     putStrLn $ "So it is unevaluated. Let us evaluate it using seq. Now we have, still at " ++ show (asBox x) ++ ":"
-    getClosureData x >>= print
-    IndClosure {indirectee = target} <- getClosureData x
+    getClosureData x >>= printInd
+    target <- indirectee `fmap` getClosureData x
     putStrLn $ "The thunk was replaced by an indirection. If we look at the target, " ++ show target ++ ", we see that it is a newly created cons-cell referencing the original location of x:"
-    getBoxedClosureData target >>= print
+    getBoxedClosureData target >>= printInd
     performGC
     putStrLn $ "After running the garbage collector (performGC), we find that the address of x is now " ++ show (asBox x) ++ " and that the self-reference is without indirections:"
-    getClosureData x >>= print
+    getClosureData x >>= printInd
 
+printInd :: Show a => a -> IO ()
+printInd x = putStrLn $ "    " ++ show x
 
 recurse :: Int -> Box -> IO ()
 recurse m = go 0