-- | Generalised Z-/n/ functions. module Music.Theory.Z where {- From GHC 7.6 onwards there is the modular-arithmetic package, which subsumes this work. {-# Language DataKinds #-} import Data.Modular {- modular-arithmetic -} import GHC.TypeLits {- base -} type Z n = Mod Integer n -- > map negate [0::Z12 .. 11] == [0,11,10,9,8,7,6,5,4,3,2,1] -- > map (+ 5) [0::Z12 .. 11] == [5,6,7,8,9,10,11,0,1,2,3,4] type Z12 = Mod Integer 12 -- > map invert [0::Z12 .. 11] == [0,11,10,9,8,7,6,5,4,3,2,1] invert :: KnownNat n => Z n -> Z n invert = negate -} import Data.List {- base -} lift_unary_Z :: Integral a => a -> (t -> a) -> t -> a lift_unary_Z z f n = mod (f n) z lift_binary_Z :: Integral a => a -> (s -> t -> a) -> s -> t -> a lift_binary_Z z f n1 n2 = mod (n1 `f` n2) z -- > import Music.Theory.Z -- > import qualified Music.Theory.Z12 as Z12 -- > z_mod 12 (6::Z12.Z12) 12 -- > z_add 12 (1::Z12.Z12) 5 -- > (1::Z12.Z12) + 5 -- > map (z_add 12 4) [1,5,6] == [5,9,10] z_add :: Integral a => a -> a -> a -> a z_add z = lift_binary_Z z (+) z_sub :: Integral a => a -> a -> a -> a z_sub z = lift_binary_Z z (-) z_mul :: Integral a => a -> a -> a -> a z_mul z = lift_binary_Z z (*) z_negate :: Integral a => a -> a -> a z_negate z = lift_unary_Z z negate z_fromInteger :: Integral a => a -> Integer -> a z_fromInteger z i = fromInteger i `mod` z z_signum :: t -> t1 -> t2 z_signum _ _ = error "Z numbers are not signed" z_abs :: t -> t1 -> t2 z_abs _ _ = error "Z numbers are not signed" -- > map (to_Z 12) [-9,-3,0] == [3,9,0] to_Z :: Integral i => i -> i -> i to_Z z = z_fromInteger z . fromIntegral from_Z :: (Integral i,Num n) => i -> n from_Z = fromIntegral -- | Z not in set. -- -- > z_complement 5 [0,2,3] == [1,4] -- > z_complement 12 [0,2,4,5,7,9,11] == [1,3,6,8,10] z_complement :: (Enum a, Eq a, Num a) => a -> [a] -> [a] z_complement z = (\\) [0 .. z - 1] z_quot :: Integral i => i -> i -> i -> i z_quot z p = to_Z z . quot p z_rem :: Integral c => c -> c -> c -> c z_rem z p = to_Z z . rem p z_div :: Integral c => c -> c -> c -> c z_div z p = to_Z z . div p -- > z_mod 12 6 12 z_mod :: Integral c => c -> c -> c -> c z_mod z p = to_Z z . mod p z_quotRem :: Integral t => t -> t -> t -> (t, t) z_quotRem z p q = (z_quot z p q,z_quot z p q) z_divMod :: Integral t => t -> t -> t -> (t, t) z_divMod z p q = (z_div z p q,z_mod z p q) z_toInteger :: Integral i => i -> i -> i z_toInteger z = to_Z z