content: {-# LANGUAGE ScopedTypeVariables, DeriveDataTypeable #-}
  module Main(main,f) where
  
  import Data.List (isPrefixOf)
  import Data.Dynamic
  import Control.Exception as E
  
  data Failure = Failure
      deriving (Show, Typeable)
  
  instance Exception Failure
  
  test = (E.throw Failure >> return ())
            `E.catch` 
         (\(x::Failure) -> return ())
  
  main :: IO ()
  main = print =<< test
  
  f :: Bool -> Bool -> Bool
  f True = error "urk"
  -- f False = \y -> y
  
  {-
  Uderlying cause: we call
  	  catch# thing handler
  and expect that (thing state-token) will
      - either diverge/throw an exception
      - or return (# x,y #)
  But it does neither: it returns a PAP, because
      thing = \p q. blah
  
  In particular, 'thing = lvl_sxo' is 
    lvl_sxc :: IO Any
    lvl_sxc = error "urk"
  
    lvl_sxo :: IO ()
      = lvl_sxc >> return ()
  
            -- inline (>>) --
  
      = (\(eta::S#). case lvl_sxc |> g1 eta of ...) |> g2
      where 
        g1 :: IO Any ~ S# -> (# S#, Any #)
        g2 :: S# -> (# S#, () #) -> IO ()
  
            -- case-of-bottomming function --
  
      = (\ (eta::S#). lvl_sxc |> g1 |> ug3) |> g2
      where 
        ug3(unsafe) :: S# -> (S#, Any) ~ (# S#, () #)
  
  This is all fine.  But it's crucial that lvl_sxc actually diverges.
  Do not eta-expand it to
  
     lvl_sxc :: IO Any
     lvl_sxc = \eta. error "urk" |> ug4
         where
           ug4(unsafe) :: S# -> (# S#, Any #) ~ IO Any
  
  In contrast, if we had
     case x of
       True  -> \a -> 3
       False -> error "urk"
  we can, and must, eta-expand the error
  
  -}