{-# LANGUAGE CPP #-}
{-# LANGUAGE DeriveDataTypeable #-}
#if __GLASGOW_HASKELL__ < 710
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE StandaloneDeriving #-}
#endif
module Data.Bin (
Bin(..),
toNatural,
fromNatural,
toNat,
fromNat,
cata,
BinP (..),
explicitShow,
explicitShowsPrec,
predP,
mult2,
mult2Plus1,
andP,
xorP,
complementBitP,
clearBitP,
bin0, bin1, bin2, bin3, bin4, bin5, bin6, bin7, bin8, bin9,
) where
import Control.DeepSeq (NFData (..))
import Data.Bits (Bits (..))
import Data.Data (Data)
import Data.Hashable (Hashable (..))
import Data.Nat (Nat (..))
import Data.Typeable (Typeable)
import GHC.Exception (ArithException (..), throw)
import Numeric.Natural (Natural)
import Data.BinP (BinP (..))
import qualified Data.Nat as N
import qualified Test.QuickCheck as QC
import qualified Data.BinP as BP
data Bin
= BZ
| BP BP.BinP
deriving (Eq, Ord, Typeable, Data)
#if __GLASGOW_HASKELL__ < 710
deriving instance Typeable 'BZ
deriving instance Typeable 'BP
#endif
instance Show Bin where
showsPrec d = showsPrec d . toNatural
instance Num Bin where
fromInteger = fromNatural . fromInteger
BZ + b = b
b@(BP _) + BZ = b
BP a + BP b = BP (a + b)
BZ * _ = BZ
_ * BZ = BZ
BP a * BP b = BP (a * b)
abs = id
signum BZ = BZ
signum (BP _) = BP BE
negate _ = error "negate @Bin"
instance Real Bin where
toRational = toRational . toInteger
instance Integral Bin where
toInteger = toInteger . toNatural
quotRem _ _ = error "quotRem @Bin is not implemented"
instance Enum Bin where
succ BZ = BP BE
succ (BP n) = BP (succ n)
pred BZ = throw Underflow
pred (BP n) = predP n
toEnum n = case compare n 0 of
LT -> throw Underflow
EQ -> BZ
GT -> BP (toEnum n)
fromEnum BZ = 0
fromEnum (BP n) = fromEnum n
instance NFData Bin where
rnf BZ = ()
rnf (BP n) = rnf n
instance Hashable Bin where
hashWithSalt = undefined
predP :: BinP -> Bin
predP BE = BZ
predP (B1 n) = BP (B0 n)
predP (B0 n) = BP (go n) where
go :: BinP
-> BinP
go BE = BE
go (B1 m) = B1 (B0 m)
go (B0 m) = B1 (go m)
mult2 :: Bin -> Bin
mult2 BZ = BZ
mult2 (BP b) = BP (B0 b)
mult2Plus1 :: Bin -> BinP
mult2Plus1 BZ = BE
mult2Plus1 (BP b) = B1 b
instance QC.Arbitrary Bin where
arbitrary = QC.frequency [ (1, return BZ), (20, fmap BP QC.arbitrary) ]
shrink BZ = []
shrink (BP b) = BZ : map BP (QC.shrink b)
instance QC.CoArbitrary Bin where
coarbitrary = QC.coarbitrary . sp where
sp :: Bin -> Maybe BinP
sp BZ = Nothing
sp (BP n) = Just n
instance QC.Function Bin where
function = QC.functionMap sp (maybe BZ BP) where
sp :: Bin -> Maybe BinP
sp BZ = Nothing
sp (BP n) = Just n
explicitShow :: Bin -> String
explicitShow n = explicitShowsPrec 0 n ""
explicitShowsPrec :: Int -> Bin -> ShowS
explicitShowsPrec _ BZ
= showString "BZ"
explicitShowsPrec d (BP n)
= showParen (d > 10)
$ showString "BP "
. BP.explicitShowsPrec 11 n
instance Bits Bin where
BZ .&. _ = BZ
_ .&. BZ = BZ
BP a .&. BP b = andP a b
BZ `xor` b = b
a `xor` BZ = a
BP a `xor` BP b = xorP a b
BZ .|. b = b
a .|. BZ = a
BP a .|. BP b = BP (a .|. b)
bit = BP . bit
clearBit BZ _ = BZ
clearBit (BP b) n = clearBitP b n
complementBit BZ n = bit n
complementBit (BP b) n = complementBitP b n
zeroBits = BZ
shiftL BZ _ = BZ
shiftL (BP b) n = BP (shiftL b n)
shiftR BZ _ = BZ
shiftR b n
| n <= 0 = b
| otherwise = shiftR (shiftR1 b) (pred n)
rotateL = shiftL
rotateR = shiftR
testBit BZ _ = False
testBit (BP b) i = testBit b i
popCount BZ = 0
popCount (BP n) = popCount n
complement _ = error "compelement @Bin is undefined"
bitSizeMaybe _ = Nothing
bitSize _ = error "bitSize @Bin is undefined"
isSigned _ = False
andP :: BinP -> BinP -> Bin
andP BE BE = BP BE
andP BE (B0 _) = BZ
andP BE (B1 _) = BP BE
andP (B0 _) BE = BZ
andP (B1 _) BE = BP BE
andP (B0 a) (B0 b) = mult2 (andP a b)
andP (B0 a) (B1 b) = mult2 (andP a b)
andP (B1 a) (B0 b) = mult2 (andP a b)
andP (B1 a) (B1 b) = BP (mult2Plus1 (andP a b))
xorP :: BinP -> BinP -> Bin
xorP BE BE = BZ
xorP BE (B0 b) = BP (B1 b)
xorP BE (B1 b) = BP (B0 b)
xorP (B0 b) BE = BP (B1 b)
xorP (B1 b) BE = BP (B0 b)
xorP (B0 a) (B0 b) = mult2 (xorP a b)
xorP (B0 a) (B1 b) = BP (mult2Plus1 (xorP a b))
xorP (B1 a) (B0 b) = BP (mult2Plus1 (xorP a b))
xorP (B1 a) (B1 b) = mult2 (xorP a b)
clearBitP :: BinP -> Int -> Bin
clearBitP BE 0 = BZ
clearBitP BE _ = BP BE
clearBitP (B0 b) 0 = BP (B0 b)
clearBitP (B0 b) n = mult2 (clearBitP b (pred n))
clearBitP (B1 b) 0 = BP (B0 b)
clearBitP (B1 b) n = BP (mult2Plus1 (clearBitP b (pred n)))
complementBitP :: BinP -> Int -> Bin
complementBitP BE 0 = BZ
complementBitP BE n = BP (B1 (bit (pred n)))
complementBitP (B0 b) 0 = BP (B1 b)
complementBitP (B0 b) n = mult2 (complementBitP b (pred n))
complementBitP (B1 b) 0 = BP (B0 b)
complementBitP (B1 b) n = BP (mult2Plus1 (complementBitP b (pred n)))
shiftR1 :: Bin -> Bin
shiftR1 BZ = BZ
shiftR1 (BP BE) = BZ
shiftR1 (BP (B0 b)) = BP b
shiftR1 (BP (B1 b)) = BP b
cata
:: a
-> a
-> (a -> a)
-> (a -> a)
-> Bin
-> a
cata z _ _ _ BZ = z
cata _ h e o (BP b) = BP.cata h e o b
toNat :: Bin -> Nat
toNat BZ = Z
toNat (BP n) = BP.toNat n
fromNat :: Nat -> Bin
fromNat = N.cata BZ succ
toNatural :: Bin -> Natural
toNatural BZ = 0
toNatural (BP bnz) = BP.toNatural bnz
fromNatural :: Natural -> Bin
fromNatural 0 = BZ
fromNatural n = BP (BP.fromNatural n)
bin0, bin1, bin2, bin3, bin4, bin5, bin6, bin7, bin8, bin9 :: Bin
bin0 = BZ
bin1 = BP BP.binP1
bin2 = BP BP.binP2
bin3 = BP BP.binP3
bin4 = BP BP.binP4
bin5 = BP BP.binP5
bin6 = BP BP.binP6
bin7 = BP BP.binP7
bin8 = BP BP.binP8
bin9 = BP BP.binP9