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 }