以下是一个完整的解决方案。它应该表现得更好,因为它的实现是基于位而不是算术运算,这是一种更有效的方法。该解决方案还尽力概括事物。
{-# LANGUAGE DefaultSignatures #-}
import Data.Bits
import Control.Monad
data Permission = IsAllowedToLogin -- 1
| IsModerator -- 2
| IsAdmin -- 4
deriving (Bounded, Enum, Eq, Show)
class ToBitMask a where
toBitMask :: a -> Int
-- | Using a DefaultSignatures extension to declare a default signature with
-- an `Enum` constraint without affecting the constraints of the class itself.
default toBitMask :: Enum a => a -> Int
toBitMask = shiftL 1 . fromEnum
instance ToBitMask Permission
instance ( ToBitMask a ) => ToBitMask [a] where
toBitMask = foldr (.|.) 0 . map toBitMask
-- | Not making this a typeclass, since it already generalizes over all
-- imaginable instances with help of `MonadPlus`.
fromBitMask ::
( MonadPlus m, Enum a, Bounded a, ToBitMask a ) =>
Int -> m a
fromBitMask bm = msum $ map asInBM $ enumFrom minBound where
asInBM a = if isInBitMask bm a then return a else mzero
isInBitMask :: ( ToBitMask a ) => Int -> a -> Bool
isInBitMask bm a = let aBM = toBitMask a in aBM == aBM .&. bm
使用以下命令运行它
main = do
print (fromBitMask 0 :: [Permission])
print (fromBitMask 1 :: [Permission])
print (fromBitMask 2 :: [Permission])
print (fromBitMask 3 :: [Permission])
print (fromBitMask 4 :: [Permission])
print (fromBitMask 5 :: [Permission])
print (fromBitMask 6 :: [Permission])
print (fromBitMask 7 :: [Permission])
print (fromBitMask 0 :: Maybe Permission)
print (fromBitMask 1 :: Maybe Permission)
print (fromBitMask 2 :: Maybe Permission)
print (fromBitMask 4 :: Maybe Permission)
输出
[]
[IsAllowedToLogin]
[IsModerator]
[IsAllowedToLogin,IsModerator]
[IsAdmin]
[IsAllowedToLogin,IsAdmin]
[IsModerator,IsAdmin]
[IsAllowedToLogin,IsModerator,IsAdmin]
Nothing
Just IsAllowedToLogin
Just IsModerator
Just IsAdmin