{-# LANGUAGE MagicHash, BangPatterns #-} module Data.Maybe.Unsafe (UnsafeMaybe ,just ,nothing ,fromMaybe ,maybe ,toMaybe) where import Unsafe.Coerce import System.IO.Unsafe import System.Mem.StableName import GHC.Prim import GHC.Types import Prelude hiding (maybe) thunk :: Int -> Int thunk x = error "bang" {-# NOINLINE thunk #-} thunkStableName :: StableName (Int -> Int) thunkStableName = unsafePerformIO (makeStableName thunk) -- | nothingSurrogate stands in for the value Nothing; we distinguish it by pointer nothingSurrogate :: Any nothingSurrogate = unsafeCoerce thunk {-# NOINLINE nothingSurrogate #-} nothingStableName :: StableName Any nothingStableName = unsafePerformIO (makeStableName nothingSurrogate) newtype UnsafeMaybe a = UnsafeMaybe Any instance Functor UnsafeMaybe where fmap f = maybe nothing (just . f) instance Applicative UnsafeMaybe where pure = just {-# INLINE pure #-} -- (UnsafeMaybe f) <*> (UnsafeMaybe x) = case reallyUnsafePtrEquality# f nothingSurrogate of -- 0# -> case reallyUnsafePtrEquality# x nothingSurrogate of -- 0# -> just ((unsafeCoerce f) (unsafeCoerce x)) -- _ -> nothing -- _ -> nothing mf <*> mx = maybe nothing (\f -> maybe nothing (just . f) mx) mf {-# INLINE (<*>) #-} instance Monad UnsafeMaybe where return = just -- (UnsafeMaybe x) >>= f = case reallyUnsafePtrEquality# x nothingSurrogate of -- 0# -> f (unsafeCoerce x) -- _ -> nothing mx >>= f = maybe nothing f mx just :: a -> UnsafeMaybe a just a = UnsafeMaybe (unsafeCoerce a) nothing :: UnsafeMaybe a nothing = UnsafeMaybe nothingSurrogate fromMaybe :: Maybe a -> UnsafeMaybe a fromMaybe (Just a) = just a fromMaybe Nothing = nothing {-# INLINE fromMaybe #-} maybe :: b -> (a -> b) -> UnsafeMaybe a -> b maybe !def transform (UnsafeMaybe !a) = case eqStableName thunkStableName named || eqStableName nothingStableName named of False -> transform (unsafeCoerce a) True -> def where named = unsafePerformIO (makeStableName a) {-# INLINE maybe #-} -- toMaybe :: UnsafeMaybe a -> Maybe a -- toMaybe (UnsafeMaybe a) = case reallyUnsafePtrEquality# a nothingSurrogate of -- 0# -> Just (unsafeCoerce a) -- _ -> Nothing -- {-# INLINE toMaybe #-} toMaybe :: UnsafeMaybe a -> Maybe a toMaybe = maybe Nothing Just