我想将枚举转换为 Int 或反转,即在 sum 类型的标签和 Int 之间实现双向映射。我已经尝试了fromEnum
但它似乎不够快,然后我尝试了unsafeCoerce
但它没有按预期工作:
import Data.Time.Clock
import Data.Int
import Unsafe.Coerce
import Control.Monad (replicateM_)
data Color = R | G | B
deriving (Enum)
main = do
printT 1 $ (unsafeCoerce R :: Int8)
printT 1000 $ (unsafeCoerce G :: Int8)
printT 1000000 $ (unsafeCoerce B :: Int8)
printT 1000000000 $ (unsafeCoerce R :: Int8)
printT 1 $ (fromEnum R)
printT 1000 $ (fromEnum G)
printT 1000000 $ (fromEnum B)
printT 1000000000 $ (fromEnum B)
---------- profile tools ------------
printT :: Show a => Int -> a -> IO ()
printT n x = print =<< timeIt n (pure x)
timeIt :: Int -> IO a -> IO a
timeIt n _ | n <= 0 = error "timeIt n | n <= 0"
timeIt n proc = do
t0 <- getCurrentTime
replicateM_ (n-1) proc
x <- proc
t1 <- getCurrentTime
putStrLn ("-- Time Used (repeat " ++ show n ++ " times): " ++ show (t1 `diffUTCTime` t0))
return x
那么最快的方法是什么呢?
你真正关心的是你的类型还是别人的类型Enum
?如果是别人的,那么你不能保证除了fromEnum
之外你可以使用任何方法,所以你不走运。如果它是你自己的类型,那么你可以使用newtype
和模式同义词而不是派生来重新实现它,这样fromEnum
实际上是免费的(前提是编译器可以在你使用它的任何地方专门化它(:
{-# LANGUAGE PatternSynonyms #-}
module ColorEnum (Color(R,G,B)) where
import Data.Coerce (coerce)
newtype Color = UnsafeColor Int
pattern R, G, B :: Color
pattern R = UnsafeColor 0
pattern G = UnsafeColor 1
pattern B = UnsafeColor 2
maxColor :: Int
maxColor = 2
instance Enum Color where
succ (UnsafeColor a)
| a == maxColor = error "succ{Color}: tried to take `succ' of last tag in enumeration"
| otherwise = UnsafeColor (a + 1)
pred (UnsafeColor a)
| a == 0 = error "pred{Color}: tried to take `pred' of first tag in enumeration"
| otherwise = UnsafeColor (a - 1)
toEnum a
| a >= 0 && a <= maxColor = UnsafeColor a
| otherwise = error $ "toEnum{Color}: tag (" ++ show a ++ ") is outside of enumeration's range (0," ++ show maxColor ++ ")"
enumFrom (UnsafeColor a) = coerce [a..maxColor]
enumFromThen (UnsafeColor a) (UnsafeColor b) = coerce [a,b..if a > b then 0 else maxColor]
fromEnum = coerce
警告:
- 这不是对你如何做基准测试的认可(事实上,正如评论者指出的那样,这可能是错误的(
- 此更改很有可能会使
fromEnum
以外的其他事情变慢 - 所有这些代码只是为了替换
data Color = R | G | B deriving (Enum)