content: -- The Game of Life
  -- (from John Launchbury)
  
  start :: [[Int]]
  start = [[],[],[],[],[],[],[],[],[],[],[],[],[],[],
           [0,0,0,1,1,1,1,1,0,1,1,1,1,1,0,1,1,1,1,1,0,1,1,1,1,1,0]]
  
  -- Calculating the next generation
  
  gen n board = map row (shift (copy n 0) board)
  
  row (last,this,next)
    = zipWith3 elt (shift 0 last) (shift 0 this) (shift 0 next)
  
  elt (a,b,c) (d,e,f) (g,h,i)
    | tot < 2 || tot > 3 = 0
    | tot == 3           = 1
    | otherwise          = e
   where
    tot = a+b+c+d+f+g+h+i
                              
  shiftr x xs = [x] ++ init xs
  shiftl x xs = tail xs ++ [x]
  shift x xs = zip3 (shiftr x xs) xs (shiftl x xs)
  
  copy 0 x = []
  copy n x = x : copy (n-1) x
  
  -- Displaying one generation
  
  disp (gen,xss) =
    gen ++ "\n\n" ++ (foldr (glue "\n") "" . map (concat . map star)) xss
  
  star 0 = "  "
  star 1 = " o"
  glue s xs ys = xs ++ s ++ ys
  
  -- Test to see if we have reached a fixpoint
  
  limit (x:y:xs) | x==y      = [x]
                 | otherwise = x : limit (y:xs)
  
  -- Generating and displaying a sequence of generations.  Rather than
  -- display all the generations, we just display the number of generations
  -- it takes to reach a fixpoint, plus the last generations.
  
  main =
    putStr (last generations)
   where
    sz = 30
    generations =
      (map disp . zip (map show [0..]) . limit . iterate (gen sz))
      (take sz (map (take sz . (++ (copy sz 0))) start ++ copy sz (copy sz 0)))
  