{-# LANGUAGE ScopedTypeVariables #-}

-----------------------------------------------------------------------------
-- |
-- Module      :  Control.Spoon
-- Copyright   :  (c) Matt Morrow & Dan Peebles
-- License     :  see LICENSE
-- 
-- Maintainer  :  pumpkingod@gmail.com
-- Stability   :  experimental
-- Portability :  non-portable (Scoped Type Variables)
--
-- Two functions for catching pureish exceptions in pure values. This library
-- considers pureish to be any error call or undefined, failed pattern matches, 
-- arithmetic exceptions, and array bounds exceptions.
--
-----------------------------------------------------------------------------


module Control.Spoon (spoon, teaspoon) where

import Control.Exception
import Control.DeepSeq
import System.IO.Unsafe

handlers :: [Handler (Maybe a)]
handlers = [ Handler $ \(_ :: ArithException) -> return Nothing
           , Handler $ \(_ :: ArrayException) -> return Nothing
           , Handler $ \(_ :: ErrorCall) -> return Nothing
           , Handler $ \(_ :: PatternMatchFail) -> return Nothing
           , Handler $ \(x :: SomeException) -> throwIO x
           ]

-- | Evaluate a value to normal form and return Nothing if any exceptions are thrown during evaluation. For any error-free value, @spoon = Just@.
spoon :: NFData a => a -> Maybe a
spoon a = unsafePerformIO $ (deepseq a (Just `fmap` return a)) `catches` handlers

-- | Like 'spoon', but only evaluates to WHNF.
teaspoon :: a -> Maybe a
teaspoon a = unsafePerformIO $ (Just `fmap` (return $! a)) `catches` handlers