%
+% (c) The University of Glasgow 2006
% (c) The GRASP/AQUA Project, Glasgow University, 1992-1998
%
-\section[UniqSupply]{The @UniqueSupply@ data type and a (monadic) supply thereof}
\begin{code}
module UniqSupply (
- UniqSupply, -- Abstractly
+ UniqSupply, -- Abstractly
- uniqFromSupply, uniqsFromSupply, -- basic ops
+ uniqFromSupply, uniqsFromSupply, -- basic ops
- UniqSM, -- type: unique supply monad
- initUs, initUs_, thenUs, thenUs_, returnUs, fixUs, getUs, withUs,
- getUniqueUs, getUniquesUs,
- mapUs, mapAndUnzipUs, mapAndUnzip3Us,
- thenMaybeUs, mapAccumLUs,
- lazyThenUs, lazyMapUs,
+ UniqSM, -- type: unique supply monad
+ initUs, initUs_,
+ lazyThenUs, lazyMapUs,
+ mapAndUnzipM,
+ MonadUnique(..),
- mkSplitUniqSupply,
- splitUniqSupply
- ) where
+ mkSplitUniqSupply,
+ splitUniqSupply, listSplitUniqSupply,
-#include "HsVersions.h"
+ -- Deprecated:
+ getUniqueUs, getUs, returnUs, thenUs, mapUs
+ ) where
import Unique
+import FastTypes
-import GLAEXTS
-import UNSAFE_IO ( unsafeInterleaveIO )
+import MonadUtils
+import Control.Monad
+import Control.Monad.Fix
+#if __GLASGOW_HASKELL__ >= 607
+import GHC.IOBase (unsafeDupableInterleaveIO)
+#else
+import System.IO.Unsafe ( unsafeInterleaveIO )
+unsafeDupableInterleaveIO :: IO a -> IO a
+unsafeDupableInterleaveIO = unsafeInterleaveIO
+#endif
-w2i x = word2Int# x
-i2w x = int2Word# x
-i2w_s x = (x :: Int#)
\end{code}
%************************************************************************
-%* *
+%* *
\subsection{Splittable Unique supply: @UniqSupply@}
-%* *
+%* *
%************************************************************************
A value of type @UniqSupply@ is unique, and it can
\begin{code}
data UniqSupply
- = MkSplitUniqSupply Int# -- make the Unique with this
- UniqSupply UniqSupply
- -- when split => these two supplies
+ = MkSplitUniqSupply FastInt -- make the Unique with this
+ UniqSupply UniqSupply
+ -- when split => these two supplies
\end{code}
\begin{code}
mkSplitUniqSupply :: Char -> IO UniqSupply
splitUniqSupply :: UniqSupply -> (UniqSupply, UniqSupply)
+listSplitUniqSupply :: UniqSupply -> [UniqSupply] -- Infinite
uniqFromSupply :: UniqSupply -> Unique
-uniqsFromSupply :: UniqSupply -> [Unique] -- Infinite
+uniqsFromSupply :: UniqSupply -> [Unique] -- Infinite
\end{code}
\begin{code}
-mkSplitUniqSupply (C# c#)
- = let
-#if __GLASGOW_HASKELL__ >= 503
- mask# = (i2w (ord# c#)) `uncheckedShiftL#` (i2w_s 24#)
-#else
- mask# = (i2w (ord# c#)) `shiftL#` (i2w_s 24#)
-#endif
- -- here comes THE MAGIC:
-
- -- This is one of the most hammered bits in the whole compiler
- mk_supply#
- = unsafeInterleaveIO (
- genSymZh >>= \ (W# u#) ->
- mk_supply# >>= \ s1 ->
- mk_supply# >>= \ s2 ->
- return (MkSplitUniqSupply (w2i (mask# `or#` u#)) s1 s2)
- )
- in
- mk_supply#
-
-foreign import ccall unsafe "genSymZh" genSymZh :: IO Word
+mkSplitUniqSupply c
+ = case fastOrd (cUnbox c) `shiftLFastInt` _ILIT(24) of
+ mask -> let
+ -- here comes THE MAGIC:
+
+ -- This is one of the most hammered bits in the whole compiler
+ mk_supply
+ = unsafeDupableInterleaveIO (
+ genSymZh >>= \ u_ -> case iUnbox u_ of { u -> (
+ mk_supply >>= \ s1 ->
+ mk_supply >>= \ s2 ->
+ return (MkSplitUniqSupply (mask `bitOrFastInt` u) s1 s2)
+ )})
+ in
+ mk_supply
+
+foreign import ccall unsafe "genSymZh" genSymZh :: IO Int
splitUniqSupply (MkSplitUniqSupply _ s1 s2) = (s1, s2)
+listSplitUniqSupply (MkSplitUniqSupply _ s1 s2) = s1 : listSplitUniqSupply s2
\end{code}
\begin{code}
-uniqFromSupply (MkSplitUniqSupply n _ _) = mkUniqueGrimily (I# n)
-uniqsFromSupply (MkSplitUniqSupply n _ s2) = mkUniqueGrimily (I# n) : uniqsFromSupply s2
+uniqFromSupply (MkSplitUniqSupply n _ _) = mkUniqueGrimily (iBox n)
+uniqsFromSupply (MkSplitUniqSupply n _ s2) = mkUniqueGrimily (iBox n) : uniqsFromSupply s2
\end{code}
%************************************************************************
-%* *
+%* *
\subsubsection[UniqSupply-monad]{@UniqSupply@ monad: @UniqSM@}
-%* *
+%* *
%************************************************************************
\begin{code}
(>>=) = thenUs
(>>) = thenUs_
+instance Functor UniqSM where
+ fmap f (USM x) = USM (\us -> case x us of
+ (r, us') -> (f r, us'))
+
+instance Applicative UniqSM where
+ pure = returnUs
+ (USM f) <*> (USM x) = USM $ \us -> case f us of
+ (ff, us') -> case x us' of
+ (xx, us'') -> (ff xx, us'')
+
-- the initUs function also returns the final UniqSupply; initUs_ drops it
initUs :: UniqSupply -> UniqSM a -> (a,UniqSupply)
initUs init_us m = case unUSM m init_us of { (r,us) -> (r,us) }
initUs_ :: UniqSupply -> UniqSM a -> a
-initUs_ init_us m = case unUSM m init_us of { (r,us) -> r }
+initUs_ init_us m = case unUSM m init_us of { (r, _) -> r }
{-# INLINE thenUs #-}
{-# INLINE lazyThenUs #-}
@thenUs@ is where we split the @UniqSupply@.
\begin{code}
-fixUs :: (a -> UniqSM a) -> UniqSM a
-fixUs m = USM (\us -> let (r,us') = unUSM (m r) us in (r,us'))
+instance MonadFix UniqSM where
+ mfix m = USM (\us -> let (r,us') = unUSM (m r) us in (r,us'))
thenUs :: UniqSM a -> (a -> UniqSM b) -> UniqSM b
thenUs (USM expr) cont
- = USM (\us -> case (expr us) of
- (result, us') -> unUSM (cont result) us')
+ = USM (\us -> case (expr us) of
+ (result, us') -> unUSM (cont result) us')
lazyThenUs :: UniqSM a -> (a -> UniqSM b) -> UniqSM b
lazyThenUs (USM expr) cont
thenUs_ (USM expr) (USM cont)
= USM (\us -> case (expr us) of { (_, us') -> cont us' })
-
returnUs :: a -> UniqSM a
returnUs result = USM (\us -> (result, us))
-withUs :: (UniqSupply -> (a, UniqSupply)) -> UniqSM a
-withUs f = USM (\us -> f us) -- Ha ha!
-
getUs :: UniqSM UniqSupply
getUs = USM (\us -> splitUniqSupply us)
+-- | A monad for generating unique identifiers
+class Monad m => MonadUnique m where
+ -- | Get a new UniqueSupply
+ getUniqueSupplyM :: m UniqSupply
+ -- | Get a new unique identifier
+ getUniqueM :: m Unique
+ -- | Get an infinite list of new unique identifiers
+ getUniquesM :: m [Unique]
+
+ getUniqueM = liftM uniqFromSupply getUniqueSupplyM
+ getUniquesM = liftM uniqsFromSupply getUniqueSupplyM
+
+instance MonadUnique UniqSM where
+ getUniqueSupplyM = USM (\us -> splitUniqSupply us)
+ getUniqueM = getUniqueUs
+ getUniquesM = getUniquesUs
+
getUniqueUs :: UniqSM Unique
getUniqueUs = USM (\us -> case splitUniqSupply us of
- (us1,us2) -> (uniqFromSupply us1, us2))
+ (us1,us2) -> (uniqFromSupply us1, us2))
getUniquesUs :: UniqSM [Unique]
getUniquesUs = USM (\us -> case splitUniqSupply us of
- (us1,us2) -> (uniqsFromSupply us1, us2))
-\end{code}
+ (us1,us2) -> (uniqsFromSupply us1, us2))
-\begin{code}
mapUs :: (a -> UniqSM b) -> [a] -> UniqSM [b]
-mapUs f [] = returnUs []
+mapUs _ [] = returnUs []
mapUs f (x:xs)
= f x `thenUs` \ r ->
mapUs f xs `thenUs` \ rs ->
returnUs (r:rs)
+\end{code}
+
+\begin{code}
+{-# -- SPECIALIZE mapM :: (a -> UniqSM b) -> [a] -> UniqSM [b] #-}
+{-# -- SPECIALIZE mapAndUnzipM :: (a -> UniqSM (b,c)) -> [a] -> UniqSM ([b],[c]) #-}
+{-# -- SPECIALIZE mapAndUnzip3M :: (a -> UniqSM (b,c,d)) -> [a] -> UniqSM ([b],[c],[d]) #-}
lazyMapUs :: (a -> UniqSM b) -> [a] -> UniqSM [b]
-lazyMapUs f [] = returnUs []
+lazyMapUs _ [] = returnUs []
lazyMapUs f (x:xs)
= f x `lazyThenUs` \ r ->
lazyMapUs f xs `lazyThenUs` \ rs ->
returnUs (r:rs)
-
-mapAndUnzipUs :: (a -> UniqSM (b,c)) -> [a] -> UniqSM ([b],[c])
-mapAndUnzip3Us :: (a -> UniqSM (b,c,d)) -> [a] -> UniqSM ([b],[c],[d])
-
-mapAndUnzipUs f [] = returnUs ([],[])
-mapAndUnzipUs f (x:xs)
- = f x `thenUs` \ (r1, r2) ->
- mapAndUnzipUs f xs `thenUs` \ (rs1, rs2) ->
- returnUs (r1:rs1, r2:rs2)
-
-mapAndUnzip3Us f [] = returnUs ([],[],[])
-mapAndUnzip3Us f (x:xs)
- = f x `thenUs` \ (r1, r2, r3) ->
- mapAndUnzip3Us f xs `thenUs` \ (rs1, rs2, rs3) ->
- returnUs (r1:rs1, r2:rs2, r3:rs3)
-
-thenMaybeUs :: UniqSM (Maybe a) -> (a -> UniqSM (Maybe b)) -> UniqSM (Maybe b)
-thenMaybeUs m k
- = m `thenUs` \ result ->
- case result of
- Nothing -> returnUs Nothing
- Just x -> k x
-
-mapAccumLUs :: (acc -> x -> UniqSM (acc, y))
- -> acc
- -> [x]
- -> UniqSM (acc, [y])
-
-mapAccumLUs f b [] = returnUs (b, [])
-mapAccumLUs f b (x:xs)
- = f b x `thenUs` \ (b__2, x__2) ->
- mapAccumLUs f b__2 xs `thenUs` \ (b__3, xs__2) ->
- returnUs (b__3, x__2:xs__2)
\end{code}