content: > {-# LANGUAGE BangPatterns,CPP #-}
  > module IOList (delete) where
  
  Goal: we want all the IORef boxes to go away in the "delete" operation
  below.  There are two versions of the code: one using the record
  selector "next", the other using a hand-written record selector
  "myNext" (see the use in delete).  Currently (6.10), neither version
  gives good code, but for different reasons.  The record selector
  version is not inlined, and the myNext version gives rise to a join
  point that takes the reboxed IORef as an argument.
  
  #define USE_UNPACK
  -- #define USE_STRICT
  
  #if defined(USE_UNPACK)
  #define UNPACK(p) {-# UNPACK #-} !(p)
  #elif defined(USE_STRICT)
  #define UNPACK(p) !(p)
  #else
  #define UNPACK(p) p
  #endif
  
  > import Data.IORef
  
  > data List a = Node { val :: a, next :: UNPACK(IORef (List a))}   
  >           | Null
  >           | Head {next :: UNPACK(IORef (List a)) }
  
  > {-# INLINE [0] myNext #-}
  > myNext :: List a -> IORef (List a)
  > myNext Node{next=n} = n
  > myNext Head{next=n} = n
  > myNext Null = error "null"
  
  > data ListHandle a = ListHandle { headList :: UNPACK(IORef (IORef (List a))),
  >                            tailList :: UNPACK(IORef (IORef (List a))) }
    
  > delete :: Eq a => ListHandle a -> a -> IO Bool
  > delete (ListHandle {headList = ptrPtr})  i = 
  >          do startptr <- readIORef ptrPtr
  >             delete2 startptr i
  >   where
  >    delete2 :: Eq a => IORef (List a) -> a -> IO Bool
  >    delete2 prevPtr i =
  >     do
  >    { prevNode <- readIORef prevPtr
  >    ; let curNodePtr = next {- or: myNext -} prevNode --  head/node have both next 
  >    ; curNode <- readIORef curNodePtr
  >    ; case curNode of
  >        Null -> return False  -- we've reached the end of the list
  >                              -- element not found
  >        Node {val = curval, next = nextNode} ->
  >          if (curval /= i) 
  >           then delete2 curNodePtr i         -- keep searching
  >           else 
  >               -- delete element (ie delink node)
  >               do { case prevNode of
  >                      Head {} -> do writeIORef prevPtr (Head {next = nextNode})
  >                                    return True
  >                      Node {} -> do writeIORef prevPtr
  >                                       (Node {val = val prevNode, next = nextNode})
  >                                    return True
  >                  }
  >     }
  