word-0.1.0.0: Data/Word/General.hs
module Data.Word.General (Word) where
import Prelude hiding (Word, reverse, (!!))
import Control.Applicative
import Control.Monad.Trans.State
import Data.Bits (Bits (..))
import Data.Bool (bool)
import Data.Fin
import Data.Fin.List hiding (swap)
import Data.Function (on)
import Data.Functor.Const (Const (..))
import Data.Functor.Identity (Identity (..))
import Data.Functor.Reverse (Reverse (..))
import Data.Maybe (fromMaybe, fromJust)
import Data.Natural.Class
import Data.Semigroup (Endo (..), Semigroup (..))
import Data.Tuple (swap)
import qualified Numeric.Natural as N
newtype Word n = Word { bits :: List n Bool }
deriving (Eq)
instance Ord (Word n) where
compare = compare `on` reverse . bits
instance Natural n => Num (Word n) where
Word as + Word bs = Word (go False as bs)
where
go :: ∀ n . Natural n => Bool -> List n Bool -> List n Bool -> List n Bool
go c = unOp₂ $ natural (Op₂ $ \ Nil Nil -> Nil) $ Op₂ $ \ (a:.as) (b:.bs) ->
let (z, c') = ((a /= b) /= c, a && b && c) in z:.go c' as bs
a * b = fromInteger . fromIntegral $ toNatural a * toNatural b
negate = (+1) . complement
abs = id
signum = fromInteger . fromIntegral . signum . toNatural
fromInteger n = case compare n 0 of
LT -> negate $ fromInteger (abs n)
EQ -> zeroBits
GT -> fromInteger (n-1) + bit 0
toNatural :: Word n -> N.Natural
toNatural = foldl (\ n b -> bool id (+1) b $ n `shiftL` 1) 0 . bits
instance Natural n => Bits (Word n) where
Word as .&. Word bs = Word (liftA2 (&&) as bs)
Word as .|. Word bs = Word (liftA2 (&&) as bs)
Word as `xor` Word bs = Word (liftA2 (/=) as bs)
complement (Word as) = Word (not <$> as)
shiftL (Word as) k = Word $ stimes k (Endo go) `appEndo` as
where go as = flip evalState False $ traverse (state . curry swap) as
shiftR (Word as) k = Word $ stimes k (Endo go) `appEndo` as
where go as = getReverse . flip evalState False $ traverse (state . curry swap) (Reverse as)
rotateL (Word as) k = Word $ stimes k (Endo go) `appEndo` as
where go as = let (bs, c) = flip runState c $ traverse (state . curry swap) as in bs
rotateR (Word as) k = Word $ stimes k (Endo go) `appEndo` as
where go as = let (Reverse bs, c) = flip runState c $ traverse (state . curry swap) (Reverse as) in bs
bitSize = fromJust . bitSizeMaybe
bitSizeMaybe _ = Just . fromIntegral . getConst $ (reify :: Const Peano n)
isSigned _ = False
testBit (Word as) = fromMaybe False . fmap (as !!) . toFinMay
bit n = Word $ maybe id (\ n -> runIdentity . at n ((pure . pure) True)) (toFinMay n) $ pure False
popCount = foldr (bool id (+1)) 0 . bits
newtype Op₂ a b n = Op₂ { unOp₂ :: List n a -> List n a -> List n b }