```{-# LANGUAGE NoImplicitPrelude, UnicodeSyntax #-}

module Data.BCD ( BCD4, unmarshalBCD4, decodeBCD ) where

--------------------------------------------------------------------------------
-- Imports
--------------------------------------------------------------------------------

-- from base:
import Prelude       ( fromInteger, fromIntegral, (-) )
import Data.Bits     ( Bits, shiftL, shiftR, bitSize )
import Data.Bool     ( otherwise )
import Data.Function ( (\$) )
import Data.List     ( map )
import Data.Ord      ( (<) )
import Data.Int      ( Int )
import Data.Word     ( Word16 )

--------------------------------------------------------------------------------
-- Binary Coded Decimals
--------------------------------------------------------------------------------

-- | A decoded 16 bits Binary Coded Decimal using 4 bits for each digit.
type BCD4 = (Int, Int, Int, Int)

-- | Decode a @Word16@ as a Binary Coded Decimal using 4 bits per digit.
unmarshalBCD4 ∷ Word16 → BCD4
unmarshalBCD4 abcd = (a, b, c, d)
where
[a, b, c, d] = map fromIntegral \$ decodeBCD 4 abcd

{-| @decodeBCD bitsInDigit bcd@ decodes the Binary Coded Decimal @bcd@ to a list
of its encoded digits. @bitsInDigit@, which is usually 4, is the number of bits
used to encode a single digit. See:
<http://en.wikipedia.org/wiki/Binary-coded_decimal>
-}
decodeBCD ∷ Bits α ⇒ Int → α → [α]
decodeBCD bitsInDigit abcd = go shftR []
where
shftR = bitSize abcd - bitsInDigit

go shftL ds | shftL < 0 = ds
| otherwise = go (shftL - bitsInDigit)
(((abcd `shiftL` shftL) `shiftR` shftR) : ds)

-- The End ---------------------------------------------------------------------
```