Skip to content

Commit 468f4e9

Browse files
committed
Simplify reifyTypeable
In GHC 8.0 and later, `KnownNat` implies `Typeable`. This lets us implement `reifyTypeable` much more easily, and probably also considerably more efficiently.
1 parent 239a6fa commit 468f4e9

File tree

1 file changed

+35
-9
lines changed

1 file changed

+35
-9
lines changed

fast/Data/Reflection.hs

Lines changed: 35 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,10 @@ import Control.Applicative
113113
import Control.Monad
114114
#endif
115115

116+
#if __GLASGOW_HASKELL__ < 800
116117
import Data.Bits
118+
import Data.Word
119+
#endif
117120

118121
#if __GLASGOW_HASKELL__ < 710
119122
import Data.Foldable
@@ -127,7 +130,6 @@ import Data.Traversable
127130
#endif
128131

129132
import Data.Typeable
130-
import Data.Word
131133
import Foreign.Ptr
132134
import Foreign.StablePtr
133135

@@ -432,7 +434,38 @@ subProxy _ _ = error "Exp.(-): undefined"
432434
-- * Typeable Reflection
433435
--------------------------------------------------------------------------------
434436

437+
stablePtrToIntPtr :: StablePtr a -> IntPtr
438+
stablePtrToIntPtr = ptrToIntPtr . castStablePtrToPtr
439+
{-# INLINE stablePtrToIntPtr #-}
440+
441+
intPtrToStablePtr :: IntPtr -> StablePtr a
442+
intPtrToStablePtr = castPtrToStablePtr . intPtrToPtr
443+
{-# INLINE intPtrToStablePtr #-}
444+
445+
446+
#if __GLASGOW_HASKELL__ >= 800
447+
-- This implementation doesn't work before 8.0 because KnownNat didn't
448+
-- imply Typeable until then.
449+
reifyTypeable :: Typeable a => a -> (forall (s :: *). (Typeable s, Reifies s a) => Proxy s -> r) -> r
450+
# if MIN_VERSION_base(4,4,0)
451+
reifyTypeable (a :: a) k = unsafeDupablePerformIO $ do
452+
# else
453+
reifyTypeable (a :: a) k = unsafePerformIO $ do
454+
# endif
455+
p <- newStablePtr a
456+
let n = stablePtrToIntPtr p
457+
reifyNat (fromIntegral n) (\(_ :: Proxy n) ->
458+
pure $ k (Proxy :: Proxy (Stable n a)))
435459

460+
data Stable (n :: Nat) a
461+
instance KnownNat n => Reifies (Stable n a) a where
462+
reflect = r where
463+
r = unsafePerformIO $ const <$> deRefStablePtr p <* freeStablePtr p
464+
p = intPtrToStablePtr $ fromIntegral $ reflect (Proxy :: Proxy n)
465+
{-# NOINLINE reflect #-}
466+
467+
#else
468+
-- We are in a world of pain
436469
class Typeable s => B s where
437470
reflectByte :: proxy s -> IntPtr
438471

@@ -492,14 +525,6 @@ stable :: p b0 -> p b1 -> p b2 -> p b3 -> p b4 -> p b5 -> p b6 -> p b7
492525
stable _ _ _ _ _ _ _ _ = Proxy
493526
{-# INLINE stable #-}
494527

495-
stablePtrToIntPtr :: StablePtr a -> IntPtr
496-
stablePtrToIntPtr = ptrToIntPtr . castStablePtrToPtr
497-
{-# INLINE stablePtrToIntPtr #-}
498-
499-
intPtrToStablePtr :: IntPtr -> StablePtr a
500-
intPtrToStablePtr = castPtrToStablePtr . intPtrToPtr
501-
{-# INLINE intPtrToStablePtr #-}
502-
503528
byte0 :: p (Stable (W b0 b1 b2 b3) w1 a) -> Proxy b0
504529
byte0 _ = Proxy
505530

@@ -570,6 +595,7 @@ reifyTypeable a k = unsafePerformIO $ do
570595
reifyByte (fromIntegral (n `shiftR` 56)) (\s7 ->
571596
reflectBefore (fmap return k) $
572597
stable s0 s1 s2 s3 s4 s5 s6 s7))))))))
598+
#endif
573599

574600

575601
data ReifiedMonoid a = ReifiedMonoid { reifiedMappend :: a -> a -> a, reifiedMempty :: a }

0 commit comments

Comments
 (0)